---
title: "The check pipeline"
description: "What mainsdk check runs on every change, the five layers of code safety, and how a change earns the Main mark."
section: "architecture"
status: "Planned for 0.2"
spec: "cli-core"
canonical: "https://mainsdk.dev/docs/architecture/the-check-pipeline"
updated: "2026-10-28"
---

# The check pipeline

> What mainsdk check runs on every change, the five layers of code safety, and how a change earns the Main mark.

Status: Planned for 0.2 · Canonical: https://mainsdk.dev/docs/architecture/the-check-pipeline · Updated: 2026-10-28

A change reaches main only when every layer passes. Each layer catches what the one before it cannot. Failures go back to your agent with the fix, so you see the result, not the noise.

## Five layers of code safety

The requirements describe five layers but name only four of them (rules, intent, outcomes, proof); "safe building blocks" below is our descriptive name for the first, and the official names may change.

```mermaid
flowchart LR
  ctx["main.context<br/>who, where, what data, what features"]
  l1["1. Safe building blocks<br/>contracts and types"]
  l2["2. Rule checks"]
  l3["3. Intent reviewers"]
  l4["4. Outcome checks<br/>locked flows, accessibility"]
  l5["5. Proof<br/>launch report, Main mark"]
  main(["main"])
  l1 --> l2 --> l3 --> l4 --> l5 --> main
  ctx -.-> l1 & l2 & l3 & l4 & l5
  l2 -- fail + fix --> agent["Your coding agent"]
  l3 -- fail + fix --> agent
  l4 -- fail + fix --> agent
```

| Layer | When it runs | What it catches | Example |
| --- | --- | --- | --- |
| 1. Safe building blocks | As the agent writes, in milliseconds | The unsafe version is impossible to write | `email.marketing()` won't compile without an unsubscribe link; data can't be queried without an owner scope |
| 2. Rule checks | As the agent writes, in milliseconds | Below-baseline code, secrets, raw `fetch`, bypassed chokepoints | `MAIN-SECRET-0002` a literal key in `app/lib/pay.ts` |
| 3. Intent reviewers | On every change before main | Code that does something other than what was asked. Reviewers use a different model or prompt from the coding agent | Hosted reviewers are paid; your own agent is free |
| 4. Outcome checks | On every change before main | Broken locked flows, missing screen states, accessibility misses | Headless browser runs of locked flows at desktop and phone widths; WCAG 2.2 AA |
| 5. Proof | When a release passes | Nothing to catch: it records the result | Launch report and the signed Main mark, `2.4.1+main27` |

## What check runs

`mainsdk check` runs every registered gate. Each interface registers its own gates through the runner, and `check` resolves and tests every overlay combination in use (for example market `in` with segment `enterprise`).

```text
mainsdk check [--env <name>] [--json] [--sarif <file>] [--fail-on <severity>]
```

It exits 0 when every gate passes, 1 when a gate fails and 2 on a usage or configuration error; see [the check](https://mainsdk.dev/docs/concepts/the-check) for flags and CI setup. The JSON output is versioned:

```jsonc
// mainsdk check --json
{ "version": 1, "project": "prj_01JC8Q…", "env": "prod", "passed": false,
  "gates": [{ "id": "secrets", "passed": false, "findings": [
    { "code": "MAIN-SECRET-0002", "severity": "critical", "file": "app/lib/pay.ts", "line": 3,
      "rule": "secrets.no_literal", "fix": "Move the key to secrets and use secret:STRIPE_KEY" } ] }] }
```

`--sarif` writes SARIF 2.1.0 so code scanning shows findings inline. Some rules worth knowing:

| Code | Rule |
| --- | --- |
| `MAIN-CHECK-0026` | A local driver resolved in production |
| `MAIN-NET-0001` | Raw network use (another HTTP client or a socket) outside the SDK |
| `MAIN-CONFIG-0010` | A layer weakens `main.org.yaml` |
| `MAIN-POLICY-0004` | A repo policy weakens an org policy |

`check` also lists every `raw()` escape hatch and every beta or experimental interface you use.

## The guarantees it holds

If it's on main:

1. No secret is in the code or the browser bundle.
2. Every endpoint checks who you are and what you're allowed to do.
3. Every record is private unless you made it public.
4. Every flow you locked still works, on desktop and phone.
5. Every minor went through age and consent checks, where your context includes minors.
6. Every marketing email can be unsubscribed from, and every SMS has a recorded opt-in.
7. Nothing that tracks runs before consent, where your regions require it.
8. Every screen handles loading, empty, error and timeout states.
9. Every package exists, is maintained and has no known vulnerability.
10. Every destructive action had a human approval.
11. Every release can roll back.

## Exceptions

An accepted finding lives in `main.yaml` with a rule, a reason, an owner and an expiry date. While it is open the mark reads "Main 27 · 1 exception", and the day after it expires `check` fails again. See [the check](https://mainsdk.dev/docs/concepts/the-check).

## Speed is a guardrail

Our target gate time is under 5 minutes. A gate that blocks wrongly or slowly gets switched off, so gate time and the false-positive rate (target under 5%) are watched as closely as safe merges.

## Later

| What | Phase |
| --- | --- |
| `mainsdk assure`: standards and industry packs, owners and deadlines, SARIF, CycloneDX, OSCAL | 2 |
| Eval suites for AI features as gates | 2 |
| Deploy admission on a required Main mark across an estate | 4 (Fleet) |

## Next

- [The check](https://mainsdk.dev/docs/concepts/the-check): flags, modes and running it in CI.
- [Check codes](https://mainsdk.dev/docs/reference/check-codes): every rule the gates report.
- [Security architecture](https://mainsdk.dev/docs/architecture/security-model): the threats each layer answers.
