Open Sites
Turn a request into a finished, published site: one opinionated stack, one workflow, one URL at the end.
<skill> below is this skill's directory. Run its scripts with absolute paths.
Stack
| Layer | Choice |
|---|---|
| Framework | vinext — Next.js App Router API (app/, Server Components, route handlers, server actions) built by Vite |
| Runtime | Cloudflare Workers: 128 MB per isolate shared by concurrent requests (including JS and WebAssembly); prefer HTTP APIs for external services — outbound TCP exists (cloudflare:sockets) but needs Worker-compatible drivers |
| UI | Tailwind 4, full shadcn/ui catalog in components/ui, lucide icons, recharts via chart |
| Data | D1 (SQLite; Drizzle for schema and migrations, prepared statements for queries) and R2 for files — only when the product needs persistence |
| Deploy | Wrangler; <name>.$OPEN_SITES_BASE_DOMAIN or <name>.<account>.workers.dev |
Setup check
Once per environment, before the first Cloudflare step, run node <skill>/scripts/doctor.mjs. If it is not ready, follow Onboarding: fix what you can, give the user one short checklist for the rest, and keep building locally meanwhile. Never print tokens or pass them as command arguments. OPEN_SITES_BASE_DOMAIN is optional; without it sites are published on workers.dev.
Ownership
One agent owns a site: its directory, dev server, storage, deploys and handoff. Delegate only bounded asset or research work (image search, image generation, fact lookup); helpers return results to the owner and never edit the site, run its scripts, deploy or spawn further agents. A background or delegated task can own a site, but then it skips the user-facing browser preview.
1. Start the project
Build a new site unless the request or context identifies an existing one. A similar site found in memory or search is not a request to reuse it.
Existing site — a directory created by this skill (wrangler.jsonc plus app/ or public/). Edit it in place; keep its package manager, lockfile, scripts, architecture and binding names. Install only when dependencies are missing or package.json/the lockfile changed. Never replace a working structure just to match the template.
New site — pick a short lowercase slug from the subject (it becomes the URL) and choose the path:
| Path | When | Command |
|---|---|---|
| Static | one self-contained page with no data, server code or build step needed | node <skill>/scripts/new-site.mjs <dir> --static |
| One-shot | new site, one route, no persistence, uploads, auth, schedules or external data | node <skill>/scripts/new-site.mjs <dir> |
| Capability | everything else: multiple routes, existing-site changes, D1/R2, auth, external data, schedules | node <skill>/scripts/new-site.mjs <dir> |
| User template | the user supplies an earlier open-sites project to start from | node <skill>/scripts/new-site.mjs <dir> --template <path> |
--name <slug> overrides the directory name; --domain <base> overrides OPEN_SITES_BASE_DOMAIN. --template copies the project's structure without Git history, env/npm credentials, local state, build output, its old address or its storage bindings; its wrangler.jsonc must be plain JSON with at most one D1 binding DB and one R2 binding BUCKET. If the output lists storage_to_recreate, run add-storage.mjs for each after installing — the copied D1 schema and migrations are reused. Then run npm ci --include=dev --include=optional --prefer-offline --no-audit --no-fund in the directory in the background and start authoring while it installs. One installer at a time; do not change dependency files while it runs.
Infer capabilities from the request; never ask the user to choose technical add-ons.
Static → full app. When a static site later needs data, server code or app-like routes: create a new full project with the same --name, port content, assets, styles and behavior into app/, validate it, then replace the static directory's contents with it (keep .git, remove obsolete files and stale output).
2. Frame the product
Plan internally and lightly while setup runs; no design interview, approval gate or design options unless the user asks to compare designs.
- Who the site is for and the primary task they need to complete.
- The essential content and requested capabilities.
- The smallest coherent scope that fully satisfies the request.
- Working surface (explore, compare, monitor, decide, act — the default for personal and internal tools; the first viewport shows core controls and a useful result) or narrative surface (publish, persuade, teach, sell, tell a story). A topic that resembles a report or article does not by itself make it narrative.
- Presentation sites (landing, marketing, portfolio, event, exhibit) get the expansion rules in Design.
Read Design before the first product edit.
Ask only when it changes the site
Ask when the request supports several plausible interpretations that would change the site's purpose, structure, content or primary interactions — being able to invent a coherent default is not enough reason to skip. Otherwise proceed.
- At most three questions in one batch, only once unless the user prompts more. Usually use all three slots when at least one question is worth asking.
- Highest-impact unknowns: purpose, audience, visitor goals, essential pages or content, required features, look and feel. Never implementation details.
- One decision or fact per question, one sentence each; prefer multiple choice over free text.
- Introduce the batch in a separate message: how the answers shape the site and that you will continue with a recommended starting point if they go unanswered.
- Ask only when the conversation can carry replies. Continue independent setup meanwhile, but do not start implementation or announce progress until the questions resolve. Unanswered → coherent assumptions.
Announce the build
Once direction is settled and before implementing features, tell the user what you are building: core features and goals grounded in their answers, plus any meaningful assumptions or additions framed as starting points they can react to. In a new paragraph give a time range: typically 2–5 minutes for static sites, 4–10 for full-stack ones.
3. Build
Stay on the delivery path
As soon as files exist, fix the scope and visual thesis and make the first real product edit while installation continues. No drafting the page twice, planning-only rounds, speculative file inspection or alternate candidate pages. Spend polish on execution inside the scope. On the one-shot path, after the first preview build the complete site in one focused pass — preferably one page and one stylesheet — then verify and publish without another polish round. Write unit tests only when asked or for genuinely risky logic. Run lint only when requested.
Start image work early
When an image brief is clear, start it in parallel and keep building. Details and budgets: Design → Imagery.
Implement
- Replace the starter placeholder (
app/page.tsxorpublic/index.html), the metadata (title, description,langinapp/layout.tsx) and the favicon with the site's own; remove unused starter-only files before publishing. - Apply the theme through the tokens in
app/globals.css(light and dark) before styling components. - Use the installed shadcn primitive for every control it covers, imported from
@/components/ui/<name>. In existing or template-derived projects, reuse only the primitives already present and keep their import paths. Map: side navigation →sidebar, views →tabs, modal flows →dialog, detail panels →sheet, destructive confirmation →alert-dialog, searchable pickers →combobox, command palette →command, booleans →switch/checkbox, fixed choices →select/radio-group, ranges →slider, contextual actions →dropdown-menu, hover help →tooltip, verification codes →input-otp, tables →table, progress →progress, paging →pagination, empty/loading →empty/skeleton, transient feedback →sonner, charts →chart.- Select by meaning; do not inventory the catalog. Open a component's source only when its API is unclear for the next edit — unfamiliarity is not a reason to hand-build a substitute.
- Compose and restyle at the call site. Do not run the shadcn CLI, install another component library or edit
components/uito obtain or restyle a primitive that is already there. - Do not invent features or state to use a component. Use semantic HTML and Tailwind for layout, art direction and UI the catalog does not cover.
- Restyling must keep each primitive's accessibility and interaction behavior.
- For capabilities beyond the primitives (complex tables, virtualization, client caching, complex forms) use Library selection. Reuse declared dependency versions; keep the lockfile in sync. Change dependencies only when the work requires it — do not prune unused packages as routine cleanup.
- Build the first viewport around the requested product, not generic dashboard chrome. Concrete, product-specific copy and realistic data. Avoid unnecessary client state; keep server-only code (database, secrets) in Server Components, route handlers and server actions.
- Add routes only when the request needs several views. Cover loading, empty, error and success states.
- Every interactive element works with keyboard and touch and has an accessible name; forms have labels and announce errors.
- The Worker entry stays an ES module whose default export has a callable
fetch(request, env, ctx)(the template'svinext/server/fetch-handler, or a custom entry that wraps it). If Cloudflare reports no registered event handlers, fix the source or build — do not redeploy the same output.
Add only requested capabilities
- Durable data — records, accounts, progress, history, uploads — uses platform storage, never
localStorage/sessionStorage/memory:node <skill>/scripts/add-storage.mjs d1|r2from the site directory, then Data. Browser storage is only for device-local preferences. - Sign-in, owner-only or identity-aware behavior: Access and auth.
- Content that must update on a schedule while nobody has the page open: Scheduled updates. Refreshing on page load needs no schedule.
- Tools for AI agents: in-page tools for the browser → WebMCP (also add them by default to new sites whose main journey lets users change data or meaningful page state); a remote MCP server hosted by the site → MCP endpoint.
- Secrets and API keys:
.dev.varslocally (git-ignored),npx wrangler secret put <NAME>for production; keep.env.example/.dev.vars.examplekeys aligned with what the code reads. Never commit values or put them in browser code. - A framework-free Worker only when the user explicitly asks for one.
4. Preview early
Where the user can see a local preview (a visible, foreground session with a user-facing preview or browser tool), start npm run dev in a long-lived terminal after installation succeeds. Show the local URL exactly once the first meaningful slice is ready — not before:
- the page lets a reasonable person recognize the requested site and its visual direction;
- theme tokens reflect the chosen direction, not the defaults;
- it shows the primary surface with representative, product-specific content — not the starter placeholder, a generic skeleton, a blank or loading-only page — and the starter's placeholder title and metadata are already replaced;
- the primary affordance is visible when the experience is interaction-led;
- the dev server renders it without a blocking error (request the exact local URL once to confirm).
The slice may be static or partly inert; defer secondary routes, full data models, exhaustive interactions, responsive refinements and animation until after the handoff — unless something is needed for recognition, security or a successful render. Once the slice is applied, fix only compile or blocking runtime errors before showing it. For a trivial request the complete site may be the slice.
For an existing site, show its current working version right away when it still represents the requested product; if the direction changes, apply the smallest representative part first. Never replace a working site with the starter.
Keep one dev server and one browser tab through all later edits. Do not scan ports or reopen the browser repeatedly. If showing the preview fails after the gate passed, say so and continue.
- An agent-only browser is for your own checks; it never counts as showing the user a preview.
- When the dev server runs on a remote machine, its
localhostis not the user's: use the environment's port forwarding or share-link tool, or tell the user the preview is unavailable. - In background or delegated tasks skip this handoff and say why.
5. Check
- Full template: the build passes (
npm run deployruns it;npm run typecheckis available when types are in doubt). - Static template: every requested page exists, local asset and link references resolve, and inline JavaScript has no syntax errors.
- WebMCP tools and scheduled jobs get the checks in their references.
- Reuse successful checks while their inputs are unchanged. Publishing needs no extra browser testing or visual QA.
6. Publish
npm run deploy
It builds once, then applies pending remote D1 migrations, uploads that build and prints the URL — a failing build never touches production. Publish new sites and every completed edit, including on later turns, unless the user asked for local-only work, saving without deploying, or no publishing.
Return the URL only from a successful deploy, otherwise report the blocker in plain language. Do not fetch the deployed site just to finish publishing. On a site's first custom-domain deploy the certificate can take a few minutes; tell the user the link may need a moment. Stop the dev server when the work is finished.
7. Communicate
Assume a nontechnical user. Talk about their site, choices, progress and results; keep commands, files, runtimes, dependencies, credentials, IDs and deployment internals out of messages unless they ask or must act.
- At most one short update per phase — preparing, building, publishing — plus one plain-language update if a phase runs past a minute.
- Recoverable technical problems stay private: say you hit a problem and are trying another way.
- Handoff for a new site: the link as
Title · domain, the main features or sections, that they can view, edit and share it, invented details and unconnected services, and one or two concrete optional next steps.
Rules
- Build only what was requested; "polished" raises execution quality, not scope. Presentation sites are the exception defined in Design. For existing sites keep their capabilities unless the request changes them.