---
title: "How MainSDK works"
description: "The four layers under every MainSDK call, and what the SDK in your app, the CLI and MainSDK Cloud each run and where."
section: "architecture"
canonical: "https://mainsdk.dev/docs/architecture/how-it-works"
updated: "2026-10-28"
---

# How MainSDK works

> The four layers under every MainSDK call, and what the SDK in your app, the CLI and MainSDK Cloud each run and where.

Canonical: https://mainsdk.dev/docs/architecture/how-it-works · Updated: 2026-10-28

MainSDK is a library you import, a CLI you run, and an optional Cloud. Every call your app makes to an interface, for example `email.send()`, passes through the same four layers inside your process. Nothing runs beside your app: there is no sidecar, daemon or extra service, and no native binary to install (ADR-0001, ADR-0066).

## Four layers under every call

```mermaid
flowchart TB
  app["Your code<br/>email.send(), db.orders.for(user), pay.checkout()"]
  subgraph sdk["Inside your app process"]
    iface["1. Interface<br/>one versioned contract, e.g. email@1.4"]
    guar["2. Guarantees<br/>unsubscribe link, owner scope, redaction, idempotency"]
    pol["3. Policy engine<br/>policy.decide(), Cedar by default, in process"]
    drv["4. Driver<br/>resend, ses, postgres, getqr.id …"]
  end
  prov["Provider API"]
  app --> iface --> guar --> pol --> drv --> prov
  pol -. decision .-> audit[("Audit log<br/>OCSF, hash-chained")]
```

| Layer | What it does | Example |
| --- | --- | --- |
| Interface | The contract you call. Written once in TypeSpec, versioned like `email@1.4` | `email.marketing({ to, template })` |
| Guarantees | Rules built into the contract, so the unsafe version is hard to write | `email.marketing()` won't compile without an unsubscribe link |
| Policy engine | The single decision point. Every interface asks it before acting | Can this user run `orders.update`? May this call reach `api.resend.com`? |
| Driver | Talks to the provider. Swapping one is a line in `main.yaml` | `providers: { email: resend }` |

Changing the provider changes only the bottom layer:

```yaml title="main.yaml"
providers:
  email: resend          # was ses: change this line, no code change
fallback:
  email: [resend, ses]   # fail over if the first is down
```

Every interface also has an escape hatch, `raw()`, that returns the provider's own client. Each use is logged, listed by `mainsdk check` and marked as bypassing that interface's guarantees.

## App, CLI and Cloud

```mermaid
flowchart LR
  subgraph you["Your machine and CI (free)"]
    cli["mainsdk CLI<br/>init · sync · check · dev · info · logs"]
    repo["Repo<br/>main.yaml · policies/ · main.lock"]
  end
  subgraph run["Where your app runs (free)"]
    sdk["mainsdk SDK<br/>interfaces, guarantees, policy engine, drivers"]
  end
  cloud["MainSDK Cloud (paid plans, phase 2)<br/>history, team views, debug loop"]
  tuf["TUF delivery<br/>baseline and market packs, driver metadata"]
  cli --> repo
  repo --> sdk
  tuf -. signed packs, background .-> sdk
  sdk -. buffered telemetry, after login and opt-in .-> cloud
```

| Part | Where it runs | What it does |
| --- | --- | --- |
| SDK (`mainsdk`) | Inside your app | Runs every call through the four layers. Never waits on our Cloud |
| CLI (`mainsdk`) | Your machine and your CI | `init` writes `main.yaml`, `sync` plans changes as a pull request, `check` runs every gate, `dev` runs offline on local drivers, `info` shows what an app is and does |
| Cloud | Our regions: US, EU, India (phase 2) | Hosted history, team views, live tail, debug sessions, replay, hosted triage |

The dotted lines are never in the request path. Packs refresh in the background, and telemetry is buffered and dropped when the Cloud is unreachable. See [request lifecycle](https://mainsdk.dev/docs/architecture/request-lifecycle).

## What is free and what is paid

What runs inside your app and your CI is free and open source under Apache-2.0: every interface, guarantee, driver, check and the policy engine. Only what we run in our Cloud is paid, and security is never metered (ADR-0007). Plans and limits are on [free and Cloud](https://mainsdk.dev/docs/concepts/free-and-cloud).

## Next

- [Request lifecycle](https://mainsdk.dev/docs/architecture/request-lifecycle): what happens on one call.
- [Core and language SDKs](https://mainsdk.dev/docs/architecture/core-and-bindings): the pure TypeScript core, and the native Rust, Python and Go SDKs that share its contracts, not its code.
- [The check pipeline](https://mainsdk.dev/docs/architecture/the-check-pipeline): what runs before a change reaches main.
