moxzi
Docs / Reference / Builder canister API

Builder canister APIalpha

What can I call on a moxzi compiler canister, and in what order?

The Candid interface of the on-chain compiler canister, grouped by what you would use it for. The authoritative copy is bin/compiler-canister/compiler.did in the repository; this page organises the same 73 methods so they can be read rather than scanned.

Most callers never touch this interface directly. moxzi build --remote <url> --canister <id> drives the whole sequence — upload, start, step, retrieve, settle — and is the supported path. Read this when you are writing a client, auditing one, or debugging a build that stopped somewhere unexpected.

The shape of a build#

A build is a job. You put sources into the canister's virtual filesystem, start a job over an entry point, drive it one step at a time until it reports #done, then pull the artifact out in chunks. Nothing about it is a single long-running call, because nothing on the Internet Computer can be: each step is a separate message under the replica's 40-billion instruction cap.

step returns a Step, which is the whole state machine:

VariantMeaning
#moreNot finished. Call step again.
#done : blobFinished. The blob is the unlinked artifact.
#err : vec MessageFailed, with structured diagnostics — code, severity, source region, notes and suggested edits.
#needClass : textThe build needs an actor-class module compiled first, named by path.

Starting a job#

MethodPurpose
start : (Options) -> (JobId)Start a job you will drive yourself with step.
startSelfDriven : (Options) -> (JobId)Start a job the canister advances on its own timer.
startEscrowed : (Options) -> (PaidStart)Quote at the CMC rate, pull the maximum a compile could cost, and record a settlement.
startPaid : (Options) -> (PaidStart)Charge the caller, then start. The pull happens first: if it fails there is no job.
cancel : (JobId) -> ()Stop a running job.

Options carries the entry path plus the same knobs the CLI exposes: debug, eop, stackBudget, forceGc, stableRegions, maxStablePages, stabilizationInstructionLimit, measureRtsStack, trapOnCallError, defaultPersistentActors, enhancedMigration and stableBaseline (the migration-chain pair — the directory is a VFS path, the baseline is the .most text itself), publicMetadata and omitMetadata, and the internal codegenInstrBudget, parseWindow and pauseBeforeCodegen.

startEscrowed is the interesting one. It pulls a maximum up front, which is what makes the compile safe to run without a per-message payment check, and refunds the difference at settleStep. See what a build costs.

Driving and watching#

MethodPurpose
step : (JobId) -> (Step)Advance the job by one message.
status : (JobId) -> (opt Status) (query)Phase name, message count, yields, instructions used.
jobStats : () -> (…)Counts across all jobs.
jobDiags : (JobId) -> (opt vec text) (query)Diagnostics recorded for a job.
sdStatus : () -> (bool, nat, text) (query)State of the self-driven job runner.
sdPoke : (JobId) -> (bool)Nudge the self-driven runner.

status is a query, and a query costs the canister a state snapshot. Poll it coarsely — the CLI's --status-secs exists to make that hard to get wrong.

Caution: sdPoke force-releases the self-driven busy flag, which makes re-entry possible. It is the one job method without a guard, and it is intended for recovering a wedged runner, not for routine driving.

Getting the artifact out#

MethodPurpose
getArtifact : (JobId) -> (opt blob) (query)The whole artifact, if it fits in one reply.
getArtifactChunk : (JobId, offset) -> (opt blob) (query)The artifact in pieces.
jobWasmSize : (JobId) -> (nat) (query)How many bytes to expect.
jobWasmChunk : (JobId, offset) -> (blob) (query)The wasm in pieces.
getCandid : (JobId) -> (opt text) (query)The generated Candid interface.
releaseJob : (JobId) -> (bool)Release the job's stored artifact.

The artifact is unlinked. Validating it will fail, and that is by design, not a bug — see linking and installing.

The virtual filesystem#

MethodPurpose
write : (path, blob) -> ()Write a file.
appendChunk : (path, blob) -> ()Append to a file, for sources larger than one message.
read : (path) -> (opt blob) (query)Read a file back.
remove : (path) -> ()Delete a file.
list : () -> (vec text) (query)Every path in your tree.
vfsStats : () -> (…) (query)Per-caller and total usage against the limits.

The VFS is per-caller. It is also canister state, which means an operator can read what you uploaded — the reason to prefer tag builds when that matters.

Content-addressed blobs and tags#

MethodPurpose
putBlobs : (vec blob) -> (vec text)Store blobs, returning their hashes.
putBlobFromFile : (path) -> (opt text)Hash a file already in the VFS into the blob store.
missingBlobs : (vec text) -> (vec text) (query)Which hashes are not stored. Upload only these.
blobHash : (blob) -> (text) (query)Hash a blob without storing it.
blobStoreStats : () -> (…)Store occupancy.
putTag / putTagFromRegister a (package, version) manifest over stored blobs.
haveTag : (text) -> (bool) (query)Is this tag registered?
tagFiles : (text) -> (opt …) (query)The files a tag names.
useTags : (vec text) -> (TagResult)Materialise registered tags into the caller's VFS.

missingBlobs is the whole point of the design: the client hashes locally, asks which hashes the canister lacks, and uploads only those. A build from an already-registered tag uploads zero bytes.

useTags accepts only mops-verified tags. Content-addressing proves a client did not lie about content; only mops can say the content really is that package version. It fails closed — no registry configured, or a tag never verified, means no build.

Provenance and verification#

MethodPurpose
verifyTag : (text) -> (opt …) (query)Re-hash every blob a tag references and confirm it still matches its key.
verifyTagAgainstMops : (text) -> (MopsCheck)Compare a registered tag against what mops published, by name and content.
tagProvenanceOf : (text) -> (opt …) (query)Who registered a tag, when, and from where.
tagMopsVerifiedAt : (text) -> (opt nat64) (query)When the tag last passed mops verification.

In MopsCheck, mismatched is the field that matters: a legitimate file path holding content mops never published. Lists are capped at 20 so the reply stays small.

Payment and settlement#

MethodPurpose
quoteEscrowFor : (sourceBytes) -> (…)What startEscrowed would pull right now, for a build of this size.
quoteEscrow : () -> (…)The older flat quote, kept for existing clients.
settleStep : (JobId) -> (SettleStep)Advance settlement by exactly one step.
getSettlement : (JobId) -> (…)Where a settlement got to.
abandonSettlement : (JobId) -> (SettleStep)Give up on a stuck settlement.
jobCharge : (JobId) -> (opt nat) (query)What a job was charged.
refundJob : (JobId) -> (…)Refund a job's charge, once. Operator-only.
getPrice, getBillingRates, revenue, icpXdrRate (queries)Current pricing and takings.

quoteEscrowFor is an update rather than a query because the rate comes from the cycles minting canister, and a query cannot make that call. It is computed server-side on purpose: a client that reimplements the escrow arithmetic drifts from it, and the drift surfaces as an insufficient-allowance failure at the worst possible moment.

Every settleStep is idempotent and records what it moved, so a caller can retry indefinitely — a failed step leaves the state untouched and the next call redoes only that step. Drive it until #done.

Operator methods#

These require the caller to be an operator. They are listed for auditability rather than use.

setPrice, setBillingRates, setChargeMultiplier, setEscrowCycles, setEscrowFloor, setEscrowPerByte, setLedger, setCmc, setMopsRegistry, setDonationSinks, setCacheVersion, clearBuildCache, getOperators, isOperatorQuery, syncOperators, getDonationSinks, buildCacheStats, installFresh.

syncOperators copies the canister's controller list into operators and is open by design: it grants nothing the controller list does not already say.

setCacheVersion identifies the compiler build. The build cache stays inert — it never serves anything — until it is set, which is what stops a compiler upgrade from serving artifacts built by the previous one.

Diagnostic and internal methods#

Present for development and incident response, not part of the supported surface: runCachedCodegen, startCachedCodegen, cgResultChunk, cgRunStatus, cgYields, codegenSnapshotReady, armCodegenTrap.

Next#

On this pageThe shape of a buildStarting a jobDriving and watchingGetting the artifact outThe virtual filesystemContent-addressed blobs and tagsProvenance and verificationPayment and settlementOperator methodsDiagnostic and internal methodsNext