Skip to main content

Provisioning

The operator-owned neutron-provision system creates and reinstalls whole Neutron canisters through one pipeline with two target adapters and the same target-neutral package bytes. It is distinct from the hosted browser Dispenser flow.

Configuration is desired state

A config is an archive-only declaration: an artifact set, and the fleet of canisters to produce from it.

It has no workspace path, no build command, and no hook. The provisioner never builds a workspace and never executes an app-owned script. Producing the archives is the trusted package/release workflow's job — a separation that exists so a provisioning run cannot be influenced by app-supplied build logic.

Two pin regimes

TargetRequirement
Local PocketIC (inline set)A kernel path and an ordered app-path list. No hashes, byte lengths, ids, or versions to maintain.
IC / external release setsComplete {path, sha256, bytes, id, version} pins, every one verified.

Loading a path-only local config keeps only its relative declarations. Only a local reinstall resolves and reads each archive, deriving its exact bytes, digest, package identity, version, and kernel-or-app role. That derived digest becomes an internal input to the compile cache, the operation fingerprint, and the deployment receipt.

Unknown artifact-set fields, duplicate ids or paths, archive drift during an operation, and symlink escapes all fail closed.

One session per config

Every writable config derives exactly one private session file, even when several configs share the repository-wide PocketIC supervisor.

It holds runtime attachment data, the sole ordered fleet mapping (index zero is the primary node), permanent IC creation or adoption evidence, the latest verified deployment, and at most one active operation.

Canister identity lives here — not in a tracked mapping directory.

Operations

There are exactly six commands. Their availability and mutation semantics differ by target.

OperationLocal PocketICIC
serveStart or attach the supervisorRejected
reinstallAlways executes, destructivePlan-only unless an execute flag is passed
authorize PRINCIPALFleet-wideRejected
statusVerify the live supervisor and session binding, then print the recorded fleetValidate and print the local journal only
createRejected — use serve, then reinstallPaid, resumable
adopt CANISTER_IDRejectedLive-verify an existing Neutron; --execute records the adoption without mutating it

IC create and reinstall are read-only plans by default. Remote mutation requires --execute; --yes is accepted only with --execute for those two commands. adopt is also plan-only by default, but its execution writes only a local verified receipt. It rejects --yes and never mutates the canister.

:::note What status actually checks On a local target, status verifies the supervisor process identity, instance availability, auto-progress, topology digest, gateway root key, and the config-to-session binding — then prints the recorded fleet from the session. It does not call each node canister.

authorize is the command that inspects every node: it checks each one's status, module hash, and controllers.

On an IC target, status intentionally makes no live IC query. Use a new create/reinstall plan, adopt, or the separate deployed-Kernel observation check when current network state must be proved. :::

The local flow

Several configs can attach their own sessions to the live supervisor rather than starting competing servers.

The separate authorize command adds and verifies a temporary principal fleet-wide without changing the deployment receipt. The next full reinstall resets each node to the developer plus the configured desired-state list — which is the intended behaviour: authorization is desired state, and a temporary grant is explicitly temporary.

Local fixtures

Fixture lifecycle is provisioner-owned and profile-specific. minimal provides the Application and trust-root infrastructure, Internet Identity, threshold-key test subnet, and a pinned local update-source asset canister whose ID is recorded in the session.

full_protocol_fixtures adds deterministic ledger/index fixtures, persistent loopback-only Bitcoin Core regtest and Foundry Anvil processes started before PocketIC, plus pinned BTC-checker, ckBTC-minter, EVM-RPC, and ckETH-minter canisters funded through their native deposit paths. Its native-chain fixture funding applies to the fleet's primary node.

None of this reintroduces a separate workspace deployment command. A Neutron reinstall only binds the recorded update-source origin.

Production creation

The IC adapter:

  1. validates pinned packages, certified subnet evidence, and the deployment identity, then compiles the complete actor in a read-only plan;
  2. shows the full spend, controller, and evidence boundary;
  3. on execution, pays the CMC and selects an exact target subnet;
  4. creates the canister and establishes its final controller set;
  5. routes chunked management calls with the child as effective canister ID;
  6. installs the already-planned actor, seeds certified assets, and binds runtime config;
  7. authorizes the deployment identity;
  8. verifies the fresh Neutron and records final deployment evidence.

The final management controller set is the deployment identity, configured backup controllers, and the Neutron itself. Kernel authorization is separate: the fresh Kernel authorizes only the deployment identity. An Internet Identity principal obtained later in the browser must be added by an already-authorized identity; the PocketIC-only authorize command does not perform that production step.

Creation evidence is permanent in the session. A completed create never creates a second canister for that session. The same session can later reset the already-paid canister without another CMC payment or creation.

Adoption and destructive reinstall

adopt CANISTER_ID is the only way to establish a session source for an existing IC Neutron. The plan live-verifies the exact current V25 runtime, module, package inventory, subnet evidence, controllers, settings, and deployer authorization. --execute repeats the proof under the operation locks and writes a private adoption receipt; it sends no ICP and changes nothing on the canister.

An IC reinstall must derive its canister ID from permanent creation or adoption evidence. It has no canister-ID override. Execution preserves the canister ID, subnet, controllers, settings, remaining cycles apart from execution costs, and the original running/stopped state, but deliberately erases all Kernel state, app data, browser authorizations, certified assets, and snapshots. It then installs and verifies the complete configured package set and authorizes only the deployment identity.

Changing desired-state config is permitted only through a fresh reinstall plan when no operation is active. An active operation must resume with the exact config, package, compiler, controller, and evidence fingerprints already bound to its journal.

Interruption recovery

Before the first irreversible IC call, the provisioner fsyncs the exact binary payload under .neutron/provision/ and records its digest in the active session operation. On a retry it reconciles ambiguous ledger, CMC, canister-creation, chunk upload, install, snapshot, module, and runtime results instead of rebuilding from mutable source or repeating a confirmed effect.

Crash recovery uses a temporary binary payload. A completed operation may remain marked active while payload cleanup is pending; rerunning the executing command finishes that cleanup. Completed operations do not retain archive JSON bundles.

Do not delete an active IC session or payload after an ambiguous response. Rerun the same command with --execute and the exact same inputs. The journal first records the verified deployment, then removes the payload, then clears the active operation, so a crash between those steps is recoverable.

Runtime binding

Once the final canister id is known, the provisioner writes the certified closed ten-field /system/runtime-config.json, containing the exact isolated-frame origin template and the update-source-origin override. PocketIC binds the exact session-recorded fixture origin. IC requires null, meaning the Kernel derives each package's verified https://<source-principal>.icp0.io origin from its manifest rather than applying a global override.

The kernel validates that record before initialising browser network clients or frames, and frame URL construction fails closed unless the result matches the certified template.

Network identity

The assembler compiles a trusted immutable installation.network_id into the actor:

  • Production derives it from the compiler-pinned IC mainnet root-key SPKI DER.
  • Local derives it from the exact status root key of the attached pinned PocketIC instance.

Runtime config, manifests, and app scripts cannot supply it. Every fleet node gets the same network identity but its own canister-bound runtime config.

The current provisioner and in-product compiler require the current V25 stable installation context. A prior stable signature that does not own that context is rejected with a clean-reinstall requirement. There is no legacy assembler acceptance path. The provisioner itself has no state-preserving upgrade command; its reinstall operations are destructive.

Certified asset restoration

Package preparation rewrites kernel files to root and package paths, app files to /app/<id>/, and shared modules to /mo/<sha256>.mo. Provisioning clears the new actor's static namespace and restores the complete file set.

Identical files resolving to one final content-addressed path are deduplicated; conflicting bytes for one path fail. Uploads may be scheduled concurrently, but each update call carries exactly one file operation or one subsequent chunk.

Deliberately unsupported

  • Per-app local CLI install, uninstall, upgrade, or unchanged no-op
  • Offline local compilation — only the attached provisioner has the verified PocketIC root context
  • Any path that runs an app-owned build script during provisioning