Lifecycle
The ordered story of a Neutron instance.
1. Create the canister
Two paths exist, for two different audiences.
Operator path — the provisioner. A configuration file names an exact set of package archives. The provisioner pays the CMC, selects a target subnet, creates the canister, compiles the complete actor from that package set, installs it, uploads and seeds the certified assets through bounded chunked operations, binds runtime configuration, authorizes the deployment identity, and verifies the result. The same machinery drives a local PocketIC fleet. See Provisioning.
Hosted path — the dispenser. Before showing a deposit address, the browser creates and saves a local Ed25519 provisioning identity and an independent one-time activation code. The user funds the derived account; the dispenser transfers ICP to the CMC, creates the canister, installs the configured starter package set, seeds its files, arms only the activation-code hash, and retires its kernel authorization and controller authority. Internet Identity is used later, at the new Neutron, not at the dispenser. See Dispenser.
Either way the canister ends up as its own controller, which is what makes self-upgrade possible.
2. Authorize the owner
Opening the canister URL loads the kernel shell. It logs in through Internet Identity and checks whether the resulting principal is in the kernel's authorization set.
On an operator-created instance, an already-authorized deployment identity can add the displayed Neutron-origin principal. On a dispenser-created instance, the activation link carries the one-time code in a fragment that the kernel removes before login. After Internet Identity authenticates, a valid code atomically authorizes the actual signed caller and is destroyed. Without either path, the kernel shows a blocking screen with the exact principal and a copy action. Once inside, Settings can add further recovery principals and IC controllers; an actual IC controller also has an explicit recovery method.
3. Install an app
This is the interesting one. An install is a reviewed, journalled, whole-canister transaction.
Three properties are worth noting:
- Compilation starts before approval. The dialog shows a compiling state and keeps the accept button disabled until a compiled Wasm size exists, so you approve something that is known to build.
- Nothing is promoted until the new code proves it is running. Staged metadata is committed only after the freshly activated actor reports the expected deployment and plan fingerprints.
- The interval is fail-closed. Between journal creation and commit, a cross-tab signal revokes frontend state and unmounts app frames in sibling tabs; every non-kernel app scope stays inactive until commit.
Full detail: Install transaction.
4. Launch an app
The launcher renders tile entries from the app registry at /system/apps.json.
Selecting one opens a new tile instance in the active workspace. Apps using the
ordinary opaque resident mode use an app-prefixed origin:
https://a<dns-app-id>a--<neutron-canister-id>.icp0.io/app/<app-id>/<tile-path>
?app=…&tile=…&instance=…&workspace=…
If the app reserves a dedicated origin for its background, tiles and trays are instead kept on the unprefixed canister origin so that the installation-bound dedicated host remains exclusive to that background. Tiles and trays stay opaque and credentialless in either case.
The kernel registers the iframe's window with a parent-owned frame context
and transfers a private MessagePort into it. The query-string values are UI
convenience only — caller identity always comes from the registered window or
port, never from anything the app says.
5. Approve calls
App frontends discover and call kernel, tile, tray, and background tools through one kernel-regulated message bus.
- A consent dialog shows the kernel-attested caller, destination canister, method, and decoded arguments before the kernel signs anything. Raw binary attachment bytes are not rendered; the dialog shows their path, size, and SHA-256 while the private transport remains bound to those exact bytes.
- Preapproved self calls let an app call its own exact declared methods with no dialog — the kernel still verifies the method belongs to that app, checks query/update mode, validates arguments against live Candid, and fixes the destination.
- Cross-app calls require a one-call or session grant, shown in a dialog naming caller, target endpoint, tool, and arguments.
- Persistent backend grants (outbound canister calls) may be approved during install when declared, or requested later through their own dialog. Both are revocable from Settings.
See Consent.
6. Update or uninstall
Owner-facing browser installs are release upgrades: a replacement must have a strictly higher packed release version. Equal versions and downgrades are rejected before compilation, and the kernel independently rejects a target below the committed version.
Uninstall uses the same journalled protocol. It stages every live managed memory root, removes app credentials and reservations only in the verified commit, and clears retired roots atomically — a trap while clearing rolls the whole commit back. A provider app cannot be uninstalled while a consumer still declares it as a dependency.
7. Replace the kernel
Installing a package whose id is kernel runs the exact same pipeline. Its web
files rewrite root assets, its manifest replaces the kernel config, and the
result is a new combined actor. It is disclosed at the highest severity the
permission display has, and it is a supported user choice.