---
title: "Your first check"
description: "Read mainsdk check output, fix a finding with a secret reference, record an expiring exception, check prod settings and run the check in CI with SARIF."
section: "getting-started"
status: "Planned for 0.2"
spec: "cli-core"
canonical: "https://mainsdk.dev/docs/getting-started/first-check"
updated: "2026-10-28"
---

# Your first check

> Read mainsdk check output, fix a finding with a secret reference, record an expiring exception, check prod settings and run the check in CI with SARIF.

Status: Planned for 0.2 · Canonical: https://mainsdk.dev/docs/getting-started/first-check · Updated: 2026-10-28

At the end of the [quickstart](https://mainsdk.dev/docs/getting-started/quickstart), `mainsdk check` passed. This page reads that output, breaks it on purpose so you see a finding, then fixes the finding properly and covers the cases you'll meet next: a gap you can't fix yet, production settings, and CI.

The check runs on your machine, free, with no account. MainSDK is pre-release; the commands here are the planned design and ship from 0.2 (see the [quickstart](https://mainsdk.dev/docs/getting-started/quickstart)).

## Run it on the clean app

```text
$ npx mainsdk check
mainsdk check · pinecart · env dev · Main 27
✓ secrets  ✓ config  ✓ policy  ✓ network  ✓ data
all gates passed · exit 0
```

Every gate that ran has one line, and exit code 0 means a pass. Run it before every pull request.

## Break it on purpose

Paste a live-looking key into a helper:

```ts title="app/lib/pay.ts"
export const stripeKey = "sk_live_51H…";
```

```text
$ npx mainsdk check
mainsdk check · pinecart · env dev · Main 27
✗ secrets    1 finding
  MAIN-SECRET-0002  critical  app/lib/pay.ts:1
  fix: Move the key to secrets and use secret:STRIPE_SECRET_KEY
✓ config  ✓ policy  ✓ network  ✓ data
1 gate failed · exit 1
```

| Part | What it tells you |
| --- | --- |
| Header | The project, the environment it resolved (`dev` unless you pass `--env`) and the baseline |
| Failed gates | Listed first. Each finding has a code, a severity, the file and line, and a fix |
| `MAIN-SECRET-0002` | A stable code. `npx mainsdk explain MAIN-SECRET-0002` prints the cause and fix offline; every code is listed in [check codes](https://mainsdk.dev/docs/reference/check-codes) |
| Passed gates | One line, so you can see what ran |
| Exit code | `0` passed, `1` a gate failed, `2` a usage or configuration error (with a `MAIN-CONFIG-` code) |

`check` resolves and tests every overlay combination you use, so a problem that exists only in `main.in.yaml` or `main.env.prod.yaml` still shows up.

## Fix the finding

Pinecart takes payments with Stripe. Put the key behind a `secret:` reference in `main.yaml` and let the `pay` interface use it on the server:

```yaml title="main.yaml"
payments: { driver: stripe }
pay:
  stripe: { key: secret:STRIPE_SECRET_KEY, webhook: secret:STRIPE_WEBHOOK_SECRET }
```

```ts title="app/lib/pay.ts"
import { pay } from "mainsdk";

export function startCheckout(orderId: string, amountInCents: number) {
  return pay.checkout({ order: orderId, amount: amountInCents, currency: "USD",
    successUrl: "/orders/done", cancelUrl: "/cart" });
}
```

For local runs, the `local` secrets driver reads values from `.mainsdk/secrets.json`, which `init` git-ignored. In production, your secrets driver (Vault, a cloud secret manager, Doppler or Infisical) supplies them. Run `npx mainsdk check` again; it exits 0, the same as before you broke it.

If the key was ever committed, rotate it with your provider: it is in your git history. See [Payments](https://mainsdk.dev/docs/interfaces/pay) and [Secrets](https://mainsdk.dev/docs/interfaces/secrets).

> **Tip:** When an agent wrote the code, let it fix it. Run `npx mainsdk check --json --agent`: it prints a stable output with the file and the fix for every finding, and a hint for how many repair rounds to allow. After three tries on the same finding, the agent is told to ask a person instead of weakening the check. See [Use MainSDK with your coding agent](https://mainsdk.dev/docs/getting-started/with-your-agent).

## When you can't fix it yet

Some gaps take time, such as a partner API that still offers only TLS 1.1. Record an exception in `main.yaml` with the rule, a reason, an owner and an expiry date:

```yaml title="main.yaml"
exceptions:
  - rule: MAIN-NET-0004
    reason: Partner gateway upgrade booked for November
    owner: "@pinecart/platform"
    expires: 2026-11-30
```

While the exception is open, `check` passes and your mark reads "Main 27 · 1 exception". The day after it expires, `check` fails again. See [Main 27 and the Main mark](https://mainsdk.dev/docs/concepts/main27).

## Check the production settings

```bash
npx mainsdk check --env prod
```

This resolves `main.env.prod.yaml` and fails with `MAIN-CHECK-0026 local driver in production: secrets` if, say, `secrets.driver` is still `local`. Set a real driver for every interface in `main.env.prod.yaml`, and the same command passes. Run it before you ship and in CI.

## Machine-readable output

```bash
npx mainsdk check --json --sarif mainsdk.sarif
```

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

The JSON is versioned and has a published schema. The SARIF file is SARIF 2.1.0, so GitHub code scanning shows each finding inline on the pull request.

## Run it in CI

Gates in your own CI are free on every plan. Check the production settings on every pull request:

```yaml title=".github/workflows/mainsdk.yml"
name: mainsdk
on: [pull_request]
permissions:
  contents: read
  security-events: write
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22 }
      - run: npm ci
      - run: npx mainsdk check --env prod --sarif mainsdk.sarif
      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with: { sarif_file: mainsdk.sarif }
```

To fail only on serious findings while you adopt, add `--fail-on <severity>`, for example `--fail-on critical`.

## Next

- [Use MainSDK with your coding agent](https://mainsdk.dev/docs/getting-started/with-your-agent)
- [The check](https://mainsdk.dev/docs/concepts/the-check)
- [Check codes](https://mainsdk.dev/docs/reference/check-codes)
