Skip to content

Take a local project to a CI artifact

This tutorial prepares a working Incan project for reproducible artifact delivery. The local gate is executable with the prepared 0.5 release envelope; the hosted runner stops at source verification until public 0.5 packaging installs that same envelope.

  1. LockFreeze dependency resolution
  2. GateMatch the local CI commands
  3. ReportDiscover the artifact
  4. HandoffSeparate shipped CI from packaging preview

Step 1: create the lock authority

From the project root, resolve dependencies and commit the result with the manifest:

incan lock
git add incan.toml incan.lock

incan.lock is the reproducibility authority for --locked commands. Regenerate it intentionally after dependency changes; do not let CI silently resolve a different graph.

Step 2: run the local gate

Run the same checks CI will enforce:

incan fmt --check .
incan test --locked
mkdir -p target
incan build src/main.incn --locked --report json --report-output target/build-report.json

Use --frozen only when the runner already has every required dependency cached. --locked prevents resolution drift while still allowing a clean runner to fetch the committed dependency graph.

Step 3: read the compiler-owned artifact path

The build report records emitted artifacts as structured rows. Select the existing binary instead of assuming a generated Cargo directory:

jq -r '.artifacts[] | select(.kind == "binary" and .exists == true) | .path' \
  target/build-report.json

The report schema is the tooling contract. Generated Rust paths remain inspectable implementation output rather than a stable ABI.

Step 4: add the hosted source-check lane

The repository composite action currently installs a compiler binary from the selected Incan source ref. It does not install the prepared 0.5 release Loaf envelope used by the local gate above. Keep the hosted lane within that smaller contract instead of publishing a workflow that is expected to fail at native execution.

Create .github/workflows/incan.yml and pin the action to the accepted Incan commit SHA:

name: Incan

on:
  push:
    branches: [main]
  pull_request:

env:
  INCAN_NO_BANNER: 1

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - name: Install Incan
        uses: encero-systems/incan/.github/actions/install-incan@<accepted-commit-sha>
      - name: Verify source contracts
        run: |
          incan --version
          incan fmt --check .
          incan check src/main.incn --format json

Do not replace the placeholder with @main: a moving compiler ref is not a reproducible delivery authority. When public 0.5 packaging installs the finite release envelope, extend this lane with the same locked test/build/report commands already verified locally and retain the report-selected artifact. Until then, the local build report proves the artifact path while hosted CI proves source and formatting contracts.

You now have a release-envelope executable local gate, a compiler-owned artifact path, and a hosted lane that stays within the installer contract actually available today. The missing hosted envelope is visible instead of hidden behind a workflow that cannot succeed.

Continue