---
title: "Prompts that work"
description: "Ten copy-paste prompts for a coding agent on MainSDK, sign-in, data, AI, uploads, MCP, payments, jobs, repairs and adoption. Each ends with a check."
section: "agents"
status: "Planned for 0.3"
spec: "fast-start"
canonical: "https://mainsdk.dev/docs/agents/prompts"
updated: "2026-10-28"
---

# Prompts that work

> Ten copy-paste prompts for a coding agent on MainSDK, sign-in, data, AI, uploads, MCP, payments, jobs, repairs and adoption. Each ends with a check.

Status: Planned for 0.3 · Canonical: https://mainsdk.dev/docs/agents/prompts · Updated: 2026-10-28

Each prompt below names the interface, the rule and the check the coding agent must run. Copy one, change the nouns, and paste it to your agent. About a minute per prompt to adapt.

MainSDK is pre-release: the commands are the planned design and do not run yet. `mainsdk check --json --agent` is planned for 0.3, `mainsdk adopt` for 0.5.

## You need

- A project with `main.yaml` and the MainSDK section in `AGENTS.md` ([setup](https://mainsdk.dev/docs/getting-started/with-your-agent)).
- A coding agent that reads `AGENTS.md`: Claude Code, Cursor, Codex or any MCP agent.

A pass is the same every time: the JSON output has `"passed": true` and the exit code is 0. A failure is not the end: the agent follows [the repair loop](https://mainsdk.dev/docs/agents/repair-loop).

## 1. Add sign-in

```text
Add sign-in to this app with the MainSDK auth interface. Run `npx mainsdk add auth` if
auth is not in main.yaml. Protect app/api/orders/route.ts with `auth.require(req)` and
scope every query with `db.orders.for(session.user)`. Do not write provider code or put
keys in files. When done, run `npx mainsdk check --json --agent` and fix every finding.
It passes when the output has "passed": true and the exit code is 0.
```

You should see: `main.yaml` gains `auth`, the route returns 401 with `MAIN-AUTH-0001` and a `fix` when signed out, and 200 when signed in.

## 2. Add a database model owned by a user

```text
Add an "invoices" model that belongs to the signed-in user. Use the MainSDK db interface:
read and write only through `db.invoices.for(session.user)`, and pass an idempotencyKey
on every create. Label any personal field in main.yaml under `db.fields.invoices`. Do not
write raw SQL and do not import a database client. Write a test with `@mainsdk/testing`
that proves a second user cannot read the first user's invoice (`MAIN-DATA-0007`). Run
`npx mainsdk check --json --agent`. It passes when "passed": true and the exit code is 0.
```

## 3. Add AI with a per-user spend limit

```text
Add a "summarise this order" feature using `ai.generate` from mainsdk. Pass `feature:
"order-summary"` and `user`. In main.yaml, set `ai.limits` with a per-user and a total
spend limit so a single user cannot run up the bill, and keep `ai.data` at training: never,
retention: zero. If an app agent makes the call, also pass `agent: "<name>"` and add
`agents.<name>.budget: { spend: $5/day, calls: 500/day }` to main.yaml. Do not import a
provider SDK. Run `npx mainsdk check --json --agent`. It passes when "passed": true and
the exit code is 0; the limits show in `npx mainsdk info`.
```

At the limit, a call fails with `MAIN-AI-0007` and nothing reaches the provider. A call that names an app agent is also charged to that agent's budget, and over it fails with `MAIN-AGENT-0002`. See [Agents with an identity, a budget and approvals](https://mainsdk.dev/docs/agents/governance).

## 4. Stream an AI reply with typed output

```text
Add a support-reply endpoint. Stream the reply to the browser with `ai.stream({ model,
messages, feature: "support-reply", user })`; use the same `ai.limits` spend limits as the
other AI features. For the triage step, call `ai.generate({ model, prompt, feature:
"ticket-triage", user, schema })` with an `s` schema, and use the typed result. Treat
model output as untrusted input: never run it as code or build a query from it. Do not
import a provider SDK. Run `npx mainsdk check --json --agent`. It passes when "passed":
true and the exit code is 0.
```

A reply that fails the schema twice throws `MAIN-AI-0011`; a stream that reaches the limit stops with `MAIN-AI-0007`. Streaming and `schema` are in the `ai@1` spec (milestone 0.3); the interface page does not show them yet, so the agent follows the spec's call shapes only.

## 5. Upload files

```text
Let signed-in users upload a receipt image. Use the MainSDK files interface with the
S3 driver (or Uploadthing, if main.yaml already uses it), key as a `secret:` reference
and a maxSize. Mint the upload target with `files.uploadUrl({ owner, maxSize, types })`
and confirm the upload with `files.complete(ref.id)` from a second route, owner set to the signed-in user. Return
links with `files.url(ref, { for: user, expiresIn: "1h" })`. Do not import a storage SDK
in route code, and do not build an upload store or a public bucket. Run
`npx mainsdk check --json --agent`. It passes when "passed": true and the exit code is 0.
```

The call shapes come from the `files` contract in the spec (`files.uploadUrl({ owner, maxSize, types, idempotencyKey? })` returns `{ method, url, headers?, fields?, ref }`; `files.complete(id)` scans the file and makes it readable). The driver is chosen in `main.yaml`; see [File uploads](https://mainsdk.dev/docs/interfaces/files) and [Upload files with S3, Uploadthing or Vercel Blob](https://mainsdk.dev/docs/guides/file-uploads).

## 6. Expose an action as an MCP tool

```text
Turn orders.list into an MCP tool for agents. Write it once with `action()` from
mainsdk: name "orders.list", an `intent`, an `s` `input`, `risk: "read"` and `mcp: true`.
Scope the data with `db.orders.for(user)`. In main.yaml add
`mcp.auth: { issuer: auth, scopes: [orders:read], token-ttl: 10m }`. Do not add a
second route that skips the action's checks. Run `npx mainsdk check --json --agent`.
It passes when "passed": true and the exit code is 0.
```

Details: [MCP server and client](https://mainsdk.dev/docs/agents/mcp).

## 7. Take a payment

```text
Add checkout for an order. Use `pay.checkout({ order, amount, currency, successUrl,
cancelUrl })` after `auth.require(req)`; amount is in integer minor units. Put the
provider key and webhook secret in main.yaml as `secret:` references. Handle
`payment.succeeded` with `pay.on()` and send slow work to `jobs.run`. Do not import a
payments SDK and do not read card data. Run `npx mainsdk check --json --agent`.
It passes when "passed": true and the exit code is 0.
```

## 8. Add a background job

```text
Move the monthly report export out of the request. Call `jobs.run("reports.export",
{ userId, month }, { idempotencyKey: "export:<userId>:<month>", retries: 3, backoff:
"exponential" })` from the route and return 202. A retry must never send or write twice.
Do not add a queue library. Run `npx mainsdk check --json --agent`. It passes when
"passed": true and the exit code is 0.
```

## 9. Fix a failing check without weakening it

```text
`npx mainsdk check` fails. Run `npx mainsdk check --json --agent`, read each finding's
file and fix, and change the code to satisfy the rule. Run `npx mainsdk explain <code>`
if a fix is unclear. Do not add an exception, lower a severity, edit baseline, delete a
gate or use `raw()` to get around a finding. If the same finding is still open after
three tries, stop and ask me. Re-run the same command. It passes when "passed": true
and the exit code is 0.
```

## 10. Adopt an existing app one module at a time

```text
Bring this app onto MainSDK with the mainsdk-adopt skill. Run `npx mainsdk adopt scan`,
then `npx mainsdk adopt report` and show me the gaps, secrets first. Run
`npx mainsdk adopt lock` before changing any code. Then migrate one module per branch
and pull request with `npx mainsdk adopt next --module <name>`, starting with secrets.
Keep what the app already runs (a sign-in provider, a database) instead of replacing
it. Never rewrite the whole app in one change. After each module run
`npx mainsdk check --json --agent`; it passes when "passed": true, the exit code is 0
and every locked flow is green. Finish with `npx mainsdk adopt finish`.
```

The scan changes no code. `adopt next` refuses to run until flows are locked (`MAIN-ADOPT-0001`). See [Adopt an existing app](https://mainsdk.dev/docs/getting-started/existing-app).

## Verify

```bash
npx mainsdk check --json --agent
```

You should see `"passed": true` and exit code 0.

## If it fails

| Code | Cause | Fix |
| --- | --- | --- |
| `MAIN-SECRET-0002` | A literal key in code | Move it to a `secret:NAME` reference in `main.yaml` |
| `MAIN-DATA-0007` | A query not scoped to the owner | Query with `db.<model>.for(user)` |
| `MAIN-AI-0007` | A spend limit was reached | Raise `ai.limits` in `main.yaml` on purpose, or wait for the period to reset |
| `MAIN-AI-0011` | Typed output failed the schema twice | Fix the schema or the prompt; never return the raw text as if valid |
| `MAIN-ADOPT-0001` | `adopt next` ran before flows were locked | Run `mainsdk adopt lock` first |

Any other code: `npx mainsdk explain <code>`.

## For agents

```text
Goal:    Do exactly what the prompt asks, on MainSDK interfaces only.
Files:   the code the change needs, plus main.yaml to declare what it uses.
Verify:  npx mainsdk check --json --agent   (pass = "passed": true and exit code 0)
Rule:    never weaken a check; never add an exception without an owner and expiry;
         after three unresolved rounds on one finding, stop and ask the developer.
Unknown: a call shape not in the docs or the skill is not yours to invent. Ask.
```

## Next

- [The repair loop](https://mainsdk.dev/docs/agents/repair-loop)
- [MCP server and client](https://mainsdk.dev/docs/agents/mcp)
- [Build with agents](https://mainsdk.dev/docs/agents)
