Quickstart

Three ways in. The app is zero-setup and needs no token, it runs on our cloud. Or self-host: the action installs cilicon from its own checkout, and uvx runs it locally, both need a cilicon.yml and your own Modal token (modal token new).

Install the app (recommended, no token)

Install the cilicon GitHub App on a repo, drop a cilicon.yml at its root, and push. Every PR gets a boot-tested check, built and booted on our cloud, so there's no Modal token and no workflow to write.

Install the cilicon app →

Self-host: as a GitHub Action

Prefer to run it on your own Modal? Add it as a step; it builds + boots the matrix and posts the check on the PR.

.github/workflows/cilicon.yml
# add cilicon as a step in your existing CI
- uses: neural-alloy/cilicon@v1
  env:
    MODAL_TOKEN_ID:     ${{ secrets.MODAL_TOKEN_ID }}
    MODAL_TOKEN_SECRET: ${{ secrets.MODAL_TOKEN_SECRET }}

Or run it locally

zsh
# nothing to install, uvx fetches and runs it in one shot
$ modal token new      # once, writes a local token
$ uvx --from git+https://github.com/neural-alloy/cilicon@v1 cilicon run
                       # build + boot every target, in parallel

# check your cilicon.yml without running anything
$ uvx --from git+https://github.com/neural-alloy/cilicon@v1 cilicon doctor
To fail a PR on a bad target, add fail-on-regression or a flash_max/ram_max budget (see Proof & gates).

cilicon.yml

A target is a toolchain plus a proof it actually ran. Adding a chip is a yaml entry, never a code change, 100+ boards and GPUs ship as presets.

cilicon.yml
targets:
  - id: firmware/stm32
    build: make
    validate: qemu_system     # boot it in QEMU
    machine: lm3s6965evb
    expect: "BOOT OK"         # the proof it booted (from the console)
    flash_max: 256K           # and fits the silicon
    ram_max: 64K

Common fields: build, validate, expect/expect_regex, flash_max/ram_max, board (a one-word preset), and matrix (sweep one spec into many cells).

Validation tiers

The validate field picks how a target is booted:

  • native / qemu_user: load the binary directly, resolve libs, reach main (an ELF-load check, not a boot).
  • qemu_system: full-system bare-metal boot in QEMU (MCUs); drive the virtual UART and assert a boot proof.
  • qemu_system_linux_aarch64: full-system Linux boot: a real ARM64 kernel boots your static ELF as init, asserted from the console (Jetson / Pi / i.MX8-class boards).
  • renode: boot on a Renode machine with modeled peripherals/sensors.
  • real_gpu: run on an actual GPU on Modal (CUDA/kernels).
  • custom: any tier cilicon hasn't heard of, via run: in pure yaml.
Every result records a fidelity (ELF_LOAD, FULL_SYSTEM_BOOT, or REAL_HARDWARE) derived from the tier, so "it booted" and "it loaded" are never confused.
Not sure it fired? cilicon doctor validates cilicon.yml and flags weak checks in 50 ms, before a cloud run.

Proof & gates

A green cilicon check isn't "it compiled", it's "it booted on the target, and here's the receipt":

  • Boot proof: a pass requires the expect string in the real console output, so the check means the artifact ran on the (emulated) chip, not that it built.
  • Size / regression gate: flash_max / ram_max fail a build that won't fit the silicon; --fail-on-regression against a baseline fails a flash/RAM/boot-time regression.
  • Signed boot attestation: --attestation (with an Ed25519 key) emits a DSSE-signed in-toto statement binding the artifact's sha256 to its boot result and fidelity. Sign where the boot happened; verify anywhere with cilicon verify-attestation.
  • Register to a fleet: a green run is a boot-proven artifact. On its own it prints registered to 0 fleets; set neural_alloy.fleet in cilicon.yml and the same signed proof is registered to your Neural Alloy fleet, the one the on-unit agent verifies before it deploys.
.github/workflows/cilicon.yml
- uses: neural-alloy/cilicon@v1
  with:
    baseline: cilicon-baseline.json   # fail on a size/boot regression
    attestation: boot.dsse.json     # signed boot proof, travels with the artifact