Site Launch
Concept → live branded landing page on a real domain, in one pass. This is the codified version of a run
that worked end to end; the fiddly API parts are scripts under scripts/ so you don't re-derive them.
Two standing rules, every run:
- Confirm before money or DNS. Buying a domain and changing DNS are outward, hard-to-undo. State what you're about to do and get an explicit yes.
- Verify after every external change — read it back.
verified:truefrom an API is a claim;curlthe live URL, re-GET the DNS zone, test-submit the form. Motion is not mutation.
Credentials (never paste in chat)
Read from env; keep them in a gitignored file the user sources, e.g. ~/.config/site-launch/env:
export VERCEL_TOKEN=vcp_... # ACCOUNT token (vcp_), NOT an AI-Gateway key (vck_) — see below
export SPACESHIP_API_KEY=... # X-API-Key
export SPACESHIP_API_SECRET=... # X-API-Secret (Spaceship needs BOTH)
If a key is missing, ask for it and tell the user exactly where to make it. Never echo a key in command output.
The pipeline
1. Frame the concept
One line: what it is, who it's for, the single CTA (email signup? book a call? buy?). Everything downstream serves that one job.
2. Name + domain → domain-scout
Invoke the domain-scout skill to generate candidates, check availability across TLDs/variants, screen
for existing-company collisions, and rank. Present the shortlist; the user picks. Prefer a clean .com or
an acceptable prefixed .com (get___, ___hq) over a bare non-.com for non-technical audiences.
3. Acquire the domain (money — confirm)
Default is manual: node scripts/spaceship.mjs buy <domain> prints the purchase link; the user buys it in
the browser and confirms. (API-buy can be added once the Spaceship purchase endpoint is verified.)
4. Build the landing page (design-pass)
Build a standalone deploy/index.html (full <!doctype> + <head> with viewport, description, OG +
Twitter meta, favicon). For real design quality, invoke impeccable or frontend-design, or apply
their laws directly: tinted neutrals (never pure #000/#fff), one committed accent, a display+body type
pair, hierarchy through scale+weight, varied spacing, no em dashes, and the bans (no side-stripe
borders, no gradient text, no glassmorphism-by-default, no identical-card grids, no hero-metric cliché).
Run the AI-slop test: if the domain alone predicts the palette, rework it.
Page must be: theme-aware (light+dark via tokens + prefers-color-scheme + [data-theme]),
responsive (clamp() padding so text never hugs edges; min-width:0 on grid/flex children or they
overflow the viewport; overflow-x:hidden on body), and clear in 5 seconds (what it is, who for, how,
who-pays above the fold).
Copy laws (field feedback from real launches):
- Assume zero knowledge. Write for a smart reader who has never heard the category's core concept. Every term the hero leans on ("AI agent", "RFP", "escrow") either gets explained or gets cut. The founder's curse is assuming the visitor shares their context — they don't.
- If the concept is novel, the first section under the fold EXPLAINS it before any stats or features: a plain-language "What is X?" with a one-paragraph definition plus a who / what / when / where / why-it-matters card row. Stats bounce off a reader who doesn't yet know what the numbers are about. (Bonus: a clean, structured definition is exactly what AI assistants cite — the explainer is AEO for the site itself.)
- Display numerals are design objects. Big stats read as one unit or they read as sloppy: sans (not
mono) with
font-variant-numeric: tabular-nums, tight tracking (≈ −.04em), unit/symbol in the accent color with normal tracking. Mono is for labels and source lines only. Group each metric visually (rule, border, or card) so number → label → source has one deliberate rhythm.
OG social image (so links preview nicely in iMessage/Slack): author a 1200×630 HTML at og/og.html,
then bash scripts/render-og.sh og/og.html deploy/og-image.png. Reference it with an ABSOLUTE url in the
meta: <meta property="og:image" content="https://<domain>/og-image.png">. Read the rendered PNG back
to confirm it looks right before shipping.
5. Deploy to Vercel
node scripts/vercel.mjs deploy deploy <project-name>
Deploys every file in deploy/ (html as text, images as base64) to production, waits for READY.
Gotcha: the token must be an ACCOUNT token (vcp_). An AI-Gateway key (vck_) authenticates but 403s
with "You don't have permission to create a project." The Vercel CLI is also flaky with tokens; this uses
the REST API on purpose.
6. Connect the domain + DNS + SSL
node scripts/vercel.mjs domain <project-name> <domain>
node scripts/vercel.mjs domain <project-name> www.<domain>
node scripts/spaceship.mjs dns-vercel <domain> # apex A -> 216.150.1.1/216.150.16.1, www CNAME -> cname.vercel-dns.com
dns-vercel cleans stale @ A / www CNAME records first (Spaceship PUT is additive), sets Vercel's CURRENT
apex IPs (the classic 76.76.21.21 is deprecated and won't serve), and reads the zone back. Vercel
auto-issues SSL once DNS resolves. Gotcha: Spaceship's CNAME field is cname, not target.
7. Wire the form backend
Default: a shared Supabase leads table (one table serves every site you launch, rows tagged
by site):
fetch("https://<project>.supabase.co/rest/v1/leads", {
method: "POST",
headers: { apikey: KEY, Authorization: "Bearer " + KEY,
"Content-Type": "application/json", Prefer: "return=minimal" },
body: JSON.stringify({ venture: "<site-slug>", website: ..., email: ...,
source: "<domain>", meta: { ts: new Date().toISOString() } })
})
Use the publishable key (client-side by design) with an RLS insert-only policy on leads — the
key can add rows, never read them. Keep the inline confirmation UI, show the thanks state even on fetch
error (never strand a submitter). Test-submit once and verify the row landed (select via the
service key or dashboard). New venture = same table, new venture slug — leads for everything live in
one queryable place instead of scattered inboxes.
8. Verify end-to-end (don't skip)
curl -sI https://<domain>→ 200, valid SSL;curlthe apex AND www.curl -sI https://<domain>/og-image.png→ 200 image/png; grep the served HTML for theog:imagemeta.- Render the page at phone width and read the screenshot — but measure overflow with a debug banner
(
scrollWidth > clientWidth), because headless Chrome has a ~500px min window and a 390-wide screenshot is a crop, not proof. - The pinch-zoom pass: recipients WILL zoom into the densest block (the stats, the pricing) and judge the craft there. Screenshot the tightest-typography section at 2× and read it like a critic — tracking, alignment, number spacing, rhythm between elements. Spacing sloppiness invisible at full-page scale is glaring at zoom, and "design and attention to detail" is exactly what a sharp visitor grades you on.
- Test-submit the form.
Output
A short recap: the live URL, the domain + DNS state, the form destination, and the rotate-your-keys reminder. The deliverable is a working site the user can share, not a description of one.
Related
domain-scout (naming + availability), impeccable / frontend-design (the page). Scripts live in
scripts/ here; they read creds from env and confirm/verify per the standing rules.