Build pipeline
sunscreen chain build (and the build phase of chain serve) runs a deterministic pipeline of stages. Each stage is gated on the previous one's success.
Stages
flowchart LR
A[anchor build<br/>or cargo build-sbf] --> B{exit 0?}
B -- no --> X[emit build_fail<br/>exit non-zero]
B -- yes --> C[IDL export<br/>idl/*.json]
C --> D{frontend declared?}
D -- no --> Z[emit build_ok<br/>exit 0]
D -- yes --> E[codama run<br/>app/src/clients/]
E --> F{exit 0?}
F -- no --> Y[emit codama_fail<br/>exit non-zero]
F -- yes --> G[touch app/.sunscreen/reload]
G --> Z
Stage 1 — Compile
- Anchor workspaces:
anchor build. Producestarget/idl/<program>.jsonandtarget/deploy/<program>.soper program. - Pinocchio workspaces:
cargo build-sbf. Produces only the.so(Pinocchio has no IDL emission yet).
Failure → emit build_fail, return Anchor's exit code (sunscreen preserves it).
Stage 2 — IDL export
For Anchor workspaces, sunscreen copies the IDL into idl/<program>.json (normalized, sorted, byte-deterministic). This is the file Codama and your CI consume.
Skipped for Pinocchio.
Stage 3 — Codama
Runs only if frontend != none in sunscreen.yml, and --no-codama was not passed.
Sunscreen manages a codama.config.mjs in the workspace root, pointing at the exported IDLs and the configured app/src/clients/ output. The command is:
pnpm exec codama run
Failure → emit codama_fail. Sunscreen does not roll back the IDL (the partial state is recoverable on the next successful build).
Stage 4 — Frontend notify
On success of stage 3, sunscreen touches app/.sunscreen/reload. Frontend dev servers (Vite, Next) watching this file trigger HMR.
If frontend != none but you don't have a dev server running, this is a harmless no-op.
NDJSON event sequence (success case)
{"event":"build_start","framework":"anchor","programs":["my_app"]}
{"event":"build_progress","step":"anchor_build"}
{"event":"build_ok","programs":["my_app"],"duration_ms":4200}
{"event":"codama_start","frontend":"react"}
{"event":"codama_ok","files_written":14,"duration_ms":850}
{"event":"frontend_notified","path":"app/.sunscreen/reload"}
chain serve extras
In serve, the pipeline runs every time the watcher emits a debounced batch:
sequenceDiagram
participant FS as Filesystem
participant W as Watcher
participant P as Pipeline
FS->>W: save event(s)
Note over W: debounce ~200ms
W->>P: run(paths)
P->>P: stages 1..4
P-->>W: result
Note over W: ready for next batch
Why this shape?
- Compile must precede everything. No IDL → nothing else can run.
- IDL is the protocol boundary. Once written, every downstream tool consumes it. Sunscreen does not feed Codama from in-memory IDL objects — the file is the contract.
- Codama is optional. Library projects without a frontend skip it. CI flags
--no-codamato keep builds fast. - Frontend notify is the last step. Any failure earlier and the frontend keeps showing the previous client.