Communitygithub.com

Open Sites

Build and publish a complete site — landing page, portfolio, dashboard, or small app — on Cloudflare Workers with a Next-style router, Tailwind, and shadcn/ui.

What is Open Sites?

A reusable site builder that takes a brief through to a live URL. It covers landing pages, portfolios, dashboards, and small tools, and adds a database and file storage when the page needs them.

Works with~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/toolittlecakes/open-sites-skill/tree/HEAD

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

What does Open Sites do?

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

LayerChoice
Frameworkvinext — Next.js App Router API (app/, Server Components, route handlers, server actions) built by Vite
RuntimeCloudflare 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
UITailwind 4, full shadcn/ui catalog in components/ui, lucide icons, recharts via chart
DataD1 (SQLite; Drizzle for schema and migrations, prepared statements for queries) and R2 for files — only when the product needs persistence
DeployWrangler; <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:

PathWhenCommand
Staticone self-contained page with no data, server code or build step needednode <skill>/scripts/new-site.mjs <dir> --static
One-shotnew site, one route, no persistence, uploads, auth, schedules or external datanode <skill>/scripts/new-site.mjs <dir>
Capabilityeverything else: multiple routes, existing-site changes, D1/R2, auth, external data, schedulesnode <skill>/scripts/new-site.mjs <dir>
User templatethe user supplies an earlier open-sites project to start fromnode <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.tsx or public/index.html), the metadata (title, description, lang in app/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/ui to 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's vinext/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|r2 from 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.vars locally (git-ignored), npx wrangler secret put <NAME> for production; keep .env.example/.dev.vars.example keys 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 localhost is 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 deploy runs it; npm run typecheck is 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.

Related Skills