---
name: deploy
description: Publish the built site to Cloudflare Pages, conversationally — preflight (node/wrangler), human-run `wrangler login`, one-time project create, a human-gated deploy, and a custom-domain walkthrough. Use when the user wants to deploy / publish / ship the site live / go live.
---

# /deploy — ship the site to Cloudflare Pages

A guided, **human-gated** deploy: from zero (no node/wrangler) to a live custom domain. You never see,
echo, log, or commit a credential — Cloudflare auth is **run by the human**, and you never deploy without
an explicit go. Walk the steps in order; degrade gracefully at each (no wrangler → guide install; no
browser → hand off the commands).

## 1. Preflight
- **Node:** `node -v` (Scrybe needs Node 18.17+). Missing/old → point to nodejs.org or `nvm`.
- **Wrangler:** `npx wrangler --version`. Missing → offer **`npm i -D wrangler`** (local dev dep, recommended)
  or `npx wrangler@latest` (no install). Don't install globally without asking.
- **Build is current:** run **`npm run build`**; confirm `dist/` exists and the build is clean. Surface the
  build's **missing-assets** and **facts-to-confirm** so they don't publish a half-finished page.

## 2. Authenticate — the HUMAN runs this; you never touch the credential
- **Primary (recommended): `wrangler login`.** Have them run **`! wrangler login`** (the `!` runs it in their
  session) — a browser opens, they approve, and wrangler stores the credential in its own config. Nothing in
  the repo, no token for you to handle.
- **Confirm (no secret printed):** `npx wrangler whoami` shows the logged-in account/email, not a secret. If it
  errors, they're not logged in yet.
- **CI / headless alternative (only if they ask):** a **scoped API token — NOT the global API key.** Create at
  Cloudflare → My Profile → API Tokens → **Account · Cloudflare Pages · Edit** (add **Zone · DNS · Edit** only if
  managing the custom domain by token). Store it as `CLOUDFLARE_API_TOKEN` (+ `CLOUDFLARE_ACCOUNT_ID`) in their
  shell/keychain. **Never** ask them to paste it to you; never echo, log, or commit it; never write it to a repo
  file. Presence-probe only — e.g. `[ -n "$CLOUDFLARE_API_TOKEN" ] && echo set`. The global API key is
  full-account access (huge blast radius) — always steer to a scoped token instead.

## 3. Project (one-time)
- Pick a project name `<project>` — suggest one from `site.config.json` `title`, lowercased/hyphenated. Set it as
  `name` in **`wrangler.toml`** (it ships with a placeholder; change it to `<project>`).
- Create it once (human-run, interactive): **`npx wrangler pages project create <name>`**.

## 4. Deploy — ONLY on an explicit "ship it"
- Never deploy automatically. After they say it: **`npx wrangler pages deploy`** (reads `wrangler.toml`, uploads
  `dist/`). It prints a `https://<name>.pages.dev` URL — report it.
- Approval is **per-publish, not standing** — ask again next time.

## 5. Custom domain — apex, www, or a subdomain
- **Ask which they want** (this changes the DNS record):
  - **Apex / root** — `example.com`
  - **www** — `www.example.com`
  - **Subdomain** — e.g. `blog.example.com`, `new.example.com` (great for a section, a second site, or staging)
- Add it (no credentials needed from you): Cloudflare dashboard → **Workers & Pages → your project → Custom
  domains → Set up a domain** → enter the exact hostname. Cloudflare provisions SSL + the DNS record:
  - **Zone already on Cloudflare** → one click (apex uses CNAME-flattening; a subdomain/www gets a CNAME automatically).
  - **DNS elsewhere** → add what it shows you at the registrar: a **CNAME `<sub>` → `<name>.pages.dev`** for a
    subdomain/www; for the **apex** use ALIAS/ANAME, or move the nameservers to Cloudflare (apex CNAMEs aren't standard).
- **apex + www:** pick one as canonical and redirect the other (Pages can serve both; a redirect keeps one for SEO).
- **Reconcile `baseUrl` — important.** The live hostname **must match `site.config.json` `baseUrl`**; it drives
  `canonical`, OpenGraph, `sitemap.xml`, `feed.xml`, and `llms.txt`. If they pick `new.example.com` but `baseUrl`
  is `https://example.com`, update `baseUrl` to the chosen host and **`npm run build` again** — otherwise every
  canonical and share-card points at the wrong domain. (Offer to make that edit + rebuild for them.)
- Walk them through it; verify by loading the hostname once it's active.

## Guardrails
- **You never see, echo, log, or commit any credential.** Auth and token creation are human-run. If a secret ever
  lands in the transcript, run the secret-leak scrub immediately and tell them.
- **Deploy is human-gated, per-publish.** No auto-deploy, no standing approval.
- **No secrets in the repo.** `.wrangler/`, `.dev.vars`, `.env` are gitignored; the credential lives in wrangler's
  own config or the shell/keychain — never a tracked file.
- **Any static host works.** Cloudflare is the paved path, but `dist/` is plain static output — Netlify, Vercel,
  GitHub Pages, or an S3/R2 bucket all serve it. If wrangler/a browser isn't available, stop at the built `dist/`
  and hand off the exact commands.
