---
title: 'AI Agent Quick Start'
description: 'Two measured, terminal-only paths for AI coding agents — a plain website (--profile site) in about a minute, or the 99-second path to a designed, database-backed homepage.'
canonical: 'https://cartwright.app/docs/getting-started/ai-quick-start'
---

# AI Agent Quick Start (/docs/getting-started/ai-quick-start)



Cartwright is the build engine AIs reach for — a real site with design, and when you want them, database and backend, live in minutes. This page is the proof, written as an executable runbook: every step is **terminal-only** (no browser required), and every step ends with a verification command so an agent knows it landed.

## Choose the door [#choose-the-door]

| The task looks like                                                                                    | Run                                                                                | Runbook          |
| ------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- | ---------------- |
| a page, a landing page, a personal or company website with content in the repo — no database, no login | `npx create-cartwright@latest my-site --yes --profile site --no-github --no-start` | **Path A** below |
| a site someone edits in a browser, a webshop, or a site an agent should operate through tools          | `npx create-cartwright@latest my-shop`                                             | **Path B** below |

Both are the same engine; the flag decides which modules are materialised into the repo.

If you are an AI coding agent: follow the steps top to bottom. If you are a human: paste this page to your agent, or run the commands yourself.

## Path A — a plain website (`--profile site`) [#path-a--a-plain-website---profile-site]

Measured cold run (Measured cold run, 2026-09-14, GitHub-hosted ubuntu-latest, create-cartwright@2.9.6, engine v0.57.0 (a9b47d4), --profile=site --ref=v0.57.0 --yes --pm=pnpm — release scaffold gate run 34820928302): scaffold + install ~22 s · `next build` ~27 s · boot to HTTP 200 with a rendered H1 ~2 s.

<Steps>
  1. **Scaffold — no database, no login, nothing to configure.**

     ```bash
     npx create-cartwright@latest my-site --yes --profile site --no-github --no-start
     cd my-site
     ```

     **Verify:**

     ```bash
     grep -q '"profile": "site"' .cartwright/profile.json && test ! -e prisma && echo site-ok
     ```

     *Proves:* no database, no admin, no auth in the repo — the profile is what it says.

  2. **Run** (in the background, so the verify can run in the same shell).

     ```bash
     pnpm dev &   # assumes :3000 is free
     ```

     **Verify** (`/` redirects to `/en`; `-L` follows):

     ```bash
     curl -sL -o /dev/null -w '%{http_code}' http://localhost:3000/
     # expect: 200
     ```

     *Proves:* it boots without needing an environment variable. The CLI still writes a generic `.env`/`.env.local` (`DATABASE_URL`, `AUTH_SECRET`, `NEXT_PUBLIC_APP_URL`); nothing in them is required by this profile — delete both and it still answers 200.

  3. **Make it say something.** Edit `website.headline` (and `tagline`, `cta`) in `brand.config.ts`, and pick a look with `designSlug` (slugs in `designs/options.ts`). For a bespoke one-page build set `designSlug: "blank"` and write `designs/blank/homepage.tsx` — its in-file guide explains the props; the header, footer, SEO and locale routing wrap whatever you render.

     **Verify:**

     ```bash
     curl -s http://localhost:3000/en | grep -o '<h1[^>]*>[^<]*'
     ```

     The `<h1>` is your `website.headline` on the shipped packs. The `blank` pack's starter homepage shows the site's name (`storeName` in `brand.config.ts`) as a placeholder heading until you replace `designs/blank/homepage.tsx` with your own markup.

  4. **Add a page** — any route under `app/[locale]/` gets the site chrome from the `[locale]` layout. Prefix internal links with `/${locale}`.

     ```tsx title="app/[locale]/trip/page.tsx"
     export default function TripPage() {
       return (
         <section className="mx-auto max-w-3xl px-6 py-16">
           <h1 className="text-3xl font-semibold">The trip</h1>
           <p className="mt-4">Timeline, map and tips go here — plain React.</p>
         </section>
       );
     }
     ```

     **Verify:** `curl -s -o /dev/null -w '%{http_code}' http://localhost:3000/en/trip` → `200`.

  5. **Build.**

     ```bash
     pnpm build
     ```

     *Proves:* plain `next build` is the whole production gate — no `db:setup`, no migration. (`pnpm start` serves the build on `:3000` once the dev server is stopped.)

  6. **Deploy.** **No environment variables are required to build and serve** (the default contact form needs `RESEND_API_KEY` + `RESEND_FROM` to deliver mail; `--with none` scaffolds without it). Set `url` in `brand.config.ts` to the real domain when you have one; on Vercel, `NEXT_PUBLIC_APP_URL` or the deployment URL wins over it for canonicals. Either push to GitHub and import the repo at vercel.com, or deploy from the terminal and keep the URL it prints:

     ```bash
     # unattended runs need a prior `npx vercel login` or VERCEL_TOKEN in the environment; unauthenticated, the next line exits 1 with an empty $URL
     URL=$(npx vercel --yes --prod | tail -n 1)   # the deployment URL is the last line of stdout
     ```

     **Verify** the deployment the same way as the local run:

     ```bash
     curl -sI "$URL/" | grep -i location               # → /en
     curl -sL -o /dev/null -w '%{http_code}' "$URL/"   # → 200
     ```

     To push the source as well: `gh repo create my-site --private --source=. --remote=origin --push`.
</Steps>

Honest limits of this door: no admin and no runtime editing (content is files), no database/auth/cart/checkout, no MCP or REST tool surface on the site itself, `/` redirects to the default locale, no map/timeline/weather sections (write those components yourself), only `Organization`/`WebSite` JSON-LD emitted by itself (builders for `FAQPage`/`HowTo`/`ItemList` and a generic `<JsonLd>` exist), not a static export (Node.js 22+ host), and the default contact form delivers mail only with Resend keys. Need a browser editor, a shop or an agent tool surface later? There is no in-place profile upgrade today — scaffold the default profile and copy `brand.config.ts` and `designs/<yours>/` across. Full page: [Build a plain website](/docs/getting-started/plain-website).

## Path B — the managed site or shop (default profile) [#path-b--the-managed-site-or-shop-default-profile]

### The measured timing [#the-measured-timing]

These numbers come from a single measured **cold run** — a fresh scaffold in a clean directory, an agent following only the documented steps below, no prior knowledge of the project. Cumulative wall-clock time:

| Step                                                              | Cumulative time |
| ----------------------------------------------------------------- | --------------- |
| Scaffold + install + database setup + seed                        | \~27 s          |
| Dev server up, homepage verified (`curl` → 200)                   | \~70 s          |
| Agent API key minted (terminal-only)                              | \~85 s          |
| Copy rendering enabled + designed look applied                    | \~90 s          |
| **Designed homepage verified (new H1 + new palette in the HTML)** | **\~99 s**      |

Your numbers will vary with hardware and network, but the shape holds: the scaffold is the fast part, and the design step is one API call.

<Steps>
  1. **Boot.**

     ```bash
     npx create-cartwright@latest my-site
     cd my-site
     pnpm dev
     ```

     `create-cartwright` installs dependencies, creates the database, and seeds an admin + demo data — the admin login is printed and saved to `.admin-credentials`. (Manual clone instead? `pnpm install && pnpm db:setup && pnpm dev`.)

     **Verify** (use your `brand.defaultLocale` — `en` in a new scaffold):

     ```bash
     curl -s -o /dev/null -w '%{http_code}' http://localhost:3000/en
     # expect: 200
     ```

     *Proves:* the app boots, the database exists, and the seed ran.

  2. **Mint an agent API key** (one-time). This unlocks the whole tool surface over REST — `POST /api/v1/tools/<name>` — without ever opening the admin UI. Keys are normally created in `/admin/api-keys`; the no-browser bootstrap is a short script that writes the key row directly:

     ```ts title="scripts/agent-key.ts"
     // Run once, then delete (or keep; it only ADDs keys).
     import { config as loadEnv } from "dotenv";
     loadEnv({ path: ".env" });
     loadEnv({ path: ".env.local", override: true });

     async function main() {
       const { generateApiKey } = await import("../lib/api-auth");
       const { prisma } = await import("../lib/db");
       const { SCOPES } = await import("../lib/scopes");
       const admin = await prisma.user.findFirst({ where: { role: "admin" } });
       if (!admin) throw new Error("No admin user — run pnpm db:setup first.");
       const { plaintext, hash } = generateApiKey();
       await prisma.apiKey.create({
         data: {
           userId: admin.id,
           name: "agent-bootstrap",
           keyHash: hash,
           scopes: JSON.stringify(SCOPES), // or a narrower list from lib/scopes.ts
         },
       });
       console.log(plaintext); // shown once — the DB stores only the hash
     }
     main().catch((e) => { console.error(e); process.exit(1); });
     ```

     ```bash
     KEY=$(pnpm exec tsx --conditions react-server scripts/agent-key.ts | tail -1)
     ```

     Two caveats that cost a cold agent real minutes when undocumented:

     * `--conditions react-server` is **required** — the project's `lib/*` modules guard with `server-only`.
     * Keep the script's imports to exactly this narrow set (`lib/api-auth`, `lib/db`, `lib/scopes`). Importing `lib/tools/registry` from a standalone script crashes on Next-only modules — call tools over REST instead.

     *Proves:* an admin exists and you now hold a scoped bearer token for the tool API.

  3. **Turn on genome copy rendering.** The designed looks in step 4 write their pre-written copy through the Resolvable Genome, and the storefront only renders genome copy when the `genomeResolve` flag is on — without it, only the palette and 3D scene change and the copy silently stays put:

     ```bash
     curl -s -X POST http://localhost:3000/api/v1/tools/features.set \
       -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
       -d '{"key":"genomeResolve","enabled":true,"confirm":true}'
     ```

     *Proves:* the tool surface works end to end (auth, scopes, confirm-token flow).

  4. **Apply a designed look** — one call, instant, no LLM involved:

     ```bash
     curl -s -X POST http://localhost:3000/api/v1/tools/magic.compose_look \
       -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
       -d '{"vertical":"cafe","confirm":true}'
     ```

     A **Voice** (in `verticals/`: `cafe`, `carpenter`, `fable`, `kindergarten`, `salon`) applies pre-written on-brand copy + a palette + a suggested design + a 3D scene in one step. To pick a specific **Skin** instead or as well, pass `"design":"<slug>"` (slugs in `designs/options.ts`) or call `design.set_slug`.

     *Proves:* the site is designed — copy, palette, layout and scene — without a browser, a designer, or a generation step.

  5. **Verify the design landed:**

     ```bash
     curl -s http://localhost:3000/en | grep -o '<h1[^>]*>[^<]*'
     ```

     The H1 and the `--color-sol-*` palette variables in the HTML should reflect the chosen look. That's the finish line: a real, designed, database-backed site serving HTML — at \~99 s on the measured cold run.
</Steps>

## Prefer a browser? [#prefer-a-browser]

The same things live in the admin UI: `/admin/designs` (skins), `/admin/verticals` (voices), `/admin/mixer` (combine skin + voice + chrome), `/admin/api-keys`, `/admin/features`. Sign in per [Sign in for the first time](/docs/getting-started/first-login).

## Where to go next [#where-to-go-next]

* [Quick Start](/docs/getting-started/quick-start) — the human-paced version of Path B's step 1.
* [From code to live](/docs/getting-started/from-code-to-live) — deploy the result to GitHub + Vercel.
* [Setup Wizard](/docs/getting-started/setup-wizard) — the guided in-admin onboarding.
