agentleFS
MelvynxMelvynx/ai-maxxing-skills/skills/create-software/SKILL.md

create-software

Skill32 starsChanged 23 days agoMITView on GitHub

Create and deploy a public web app on Cloudflare with TanStack Start, shadcn/ui, Convex, Better Auth, Lumail and optional Stripe, with an admin area, API and CLI so AI controls it. Use when asked to build or ship a SaaS, course platform, membership or client portal people sign up to or pay for.

  • Reads credentials
  • Installs packages
  • Sends data out

The file

We split this skill into the rules it gives an agent

8 rules. About 0 are common, 3 are distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Keep this stack unless the user asks to swap a layer:

    line 13
  2. Very specific:

    Check access and fix what fails with the matching setup skill (setup-github, setup-cloudflare, setup-convex, setup-lumail, setup-node when …

    line 30
  3. Very specific:

    Always write the confirmed brief to SPEC.md at the app root, before any code, so every later conversation starts from it:

    line 40
  4. Very specific:

    Add an AGENTS.md at the app root that says: read SPEC.md before any change.

    line 45
  5. Distinctive:

    Keep double opt-in only for a cold form (newsletter or waitlist where the email is not verified).

    line 62
  6. Very specific:

    Create the sending domain with lumail domain --help and add the DNS records it returns in Cloudflare yourself (unproxied).

    line 63
  7. Very specific:

    If the app sells, start with a fake checkout until the user gives Stripe test keys, then real Checkout and a signed webhook in …

    line 67
  8. Distinctive:

    Add a clean error page, a 404 page, a favicon and page titles.

    line 68

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Build a working web app on the user's own accounts and put it live on their Cloudflare domain. Do every step yourself with the CLIs and only ask for what needs a human (a browser login, a device code, a payment, a secret key). Talk to the user in their language, short messages, no jargon. For a private tool only the user and their agent use, switch to create-internal-app; for a page with no sign-in, switch to create-landing.

If you got this skill from a link instead of a local folder, install nothing else from the repo: download a file it links only when a step needs it, with curl -fsSL https://raw.githubusercontent.com/Melvynx/ai-maxxing-skills/main/skills/create-software/<path> -o <scratch>/<file> (for example references/fast-app.md), and read another skill it names only when you reach it, from https://raw.githubusercontent.com/Melvynx/ai-maxxing-skills/main/skills/<skill-name>/SKILL.md.

Keep this stack unless the user asks to swap a layer:

  • App, routing, server functions: TanStack Start (React, TypeScript, Vite).
  • UI: shadcn/ui on Base UI + Tailwind CSS v4, lucide-react icons, sonner toasts.
  • Database, backend, files, crons: Convex for everything, no other database or API server.
  • Auth: Better Auth through @convex-dev/better-auth, email OTP by default.
  • Marketing and login emails: Lumail through @lumail/convex.
  • Payments, only if the app sells: Stripe Checkout with the stripe-checkout skill.
  • Video: Tella embeds from the URL the user pastes.
  • Hosting, domain, DNS: Cloudflare Workers with @cloudflare/vite-plugin, deployed with cf.
  • Code: Git and one private GitHub repo.
  • Control by AI: an admin area at /admin, an API at /api/v1 with API keys, and a CLI named after the app with its <app>-cli skill.

Every app is built so the user's AI can run it, not only the user's mouse. Always build, and always explain to the user in one plain sentence, the admin part: an /admin area for the owner, a clean API reached with API keys, and a CLI plus skill so their agent controls the whole app from the terminal, like Lumail (admin pages, /api/admin/*, admin keys, the lumail CLI). Anything the owner can do in /admin, the API and the CLI can do too. This is never optional and never cut from v1. Details in references/admin-api-cli.md.

Reach for the TanStack library before any other package for client jobs: @tanstack/react-query + @convex-dev/react-query (convexQuery(api.x.y, args)) for fetching and cache, @tanstack/react-table for lists, sorting, filters and pagination, @tanstack/react-virtual for long lists, @tanstack/react-form + zod for forms, @tanstack/markdown to render markdown, @tanstack/react-hotkeys for shortcuts (cmd+k, j/k, esc), @tanstack/react-pacer to debounce search and throttle saves, @tanstack/ai-react for AI chat or generation. Check each package's current API (npm view <pkg> version, then its README or find-docs) instead of writing it from memory.

  1. Check access and fix what fails with the matching setup skill (setup-github, setup-cloudflare, setup-convex, setup-lumail, setup-node when npx is missing) before writing code. When a login needs the browser, give the exact link or code and wait for "done".

    git --version && gh auth status       # GitHub
    cf --version && cf auth whoami        # Cloudflare (npm i -g cf, then cf auth login)
    npx convex --version                  # Convex (npx convex login when building)
    npx lumail@latest auth test           # Lumail (npx lumail@latest setup --authenticate)
  2. Decide first, with the user: does this app need organizations (multi-tenant)? Team members, shared data, roles, invitations, billing per company or API keys per workspace mean yes; a single-user tool means no. Yes changes every table, query and URL from day 1, so follow references/organizations.md. Then run the grill-me skill and build only once the user confirms the brief; skip it only if a brief was already confirmed in this conversation. Defaults: landing at /, app at /app (/:org/... with organizations), admin at /admin, English UI, OTP sign-in, the user is the only admin. When you show the brief, tell the user the app comes with an admin area, an API and a CLI so their AI can manage everything, and ask what they will want their AI to do in it (for example "list today's sales", "refund an order", "ban a user").
  3. Always write the confirmed brief to SPEC.md at the app root, before any code, so every later conversation starts from it:
    • The brief: goal, who uses it, the user story screen by screen, every screen, the data objects and their fields, what is out of v1, and what "done" means for the user.
    • An ## Admin, API, CLI section: every admin page, every API route (GET /api/v1/admin/users...) and the CLI command that matches it, from what the user wants their AI to do.
    • A ## Tasks checklist, very precise: one small change per box, named by its route, screen, field or Convex function, each with a Check: line saying how to prove it works on the real app. Write - [ ] /app/lessons lists lessons in a table, newest first, 20 per page. Check: with 25 lessons, page 2 shows 5, never - [ ] lessons page.
    • Go through references/product-rules.md (URLs, access, search, composer, tags, agents, webhooks, email rendering, deploy) and add a task for every rule that applies.
    • Add an AGENTS.md at the app root that says: read SPEC.md before any change; for a new feature or fix, add its tasks to SPEC.md first, then build; after building or changing any screen, run better; never stop until every task matches.
  4. Scaffold TanStack Start + Tailwind + npx shadcn@latest init (Base UI flavor) and add components with npx shadcn@latest add. git init, then gh repo create <name> --private --source . --push.
  5. Run npx convex dev --once to create the project and .env.local. Write one schema.ts with an index for every query. Every public function checks the signed-in user and ownership server-side, anything only the server calls is internal*, and reads are bounded with .take(n) or .paginate(). With organizations, every table has orgId and every function checks membership and role. See the convex skill.
  6. Wire Better Auth: register both components in convex/convex.config.ts (app.use(betterAuth), app.use(lumail)), createAuth with authComponent.adapter(ctx), the emailOTP plugin and the convex({ authConfig }) plugin, routes via authComponent.registerRoutes(http, createAuth), BETTER_AUTH_SECRET and SITE_URL as Convex env vars. Protect /app in the route beforeLoad and again in every Convex function.
  7. Wire Lumail in one convex/email.ts that holds every call. Create LUMAIL_API_KEY yourself with lumail tokens --help; it never reaches the browser.
    • Login codes: sendVerificationOTP schedules an internal mutation that calls lumail.sendEmail(ctx, { ..., transactional: true }). Without a key, log the code to the Convex console so local dev still works.
    • Signups: in Better Auth databaseHooks.user.create.after, upsert the person with lumail.upsertSubscriber(ctx, { email, tags: ["<app-slug>-user"], triggerWorkflows: true }).
    • Skip double opt-in for anyone who signs in or buys, since the OTP or the payment proves they own the email: they go straight to "subscribed" and tag workflows fire right away. The component cannot pass that flag, so also call the API from an internal action:

      await fetch("https://lumail.io/api/v1/subscribers", {
        method: "POST",
        headers: { Authorization: `Bearer ${process.env.LUMAIL_API_KEY}`, "Content-Type": "application/json" },
        body: JSON.stringify({ email, skipDoubleOptIn: true }),
      });
    • Keep double opt-in only for a cold form (newsletter or waitlist where the email is not verified).
    • Create the sending domain with lumail domain --help and add the DNS records it returns in Cloudflare yourself (unproxied). More in the lumail skill.
  8. Put data on screen with useSuspenseQuery(convexQuery(...)) so the UI updates live, lists in TanStack Table, forms in TanStack Form calling Convex mutations, toasts on success and error. Build every screen, admin included, to references/design-system-rules.md. After building any screen, run the better skill on it, in light and dark, and finish its screenshot loop before moving on.
  9. Build the admin area, API keys, API and CLI with references/admin-api-cli.md: each action is one internal Convex function called by the admin page and by the API, keys stored hashed and shown once, /api/v1 on the app domain, cli/<app>.mjs installed with npm install -g ./cli, then the <app>-cli skill in ~/.agents/skills. Every new feature later gets its admin view, route and CLI command in the same change.
  10. Make it fast on every page with references/fast-app.md: defaultPreload: "intent", a 30 s query cache, a loader on detail pages, a custom pendingComponent skeleton on every route that matches the real layout, a loading state on every async button, indexed and bounded Convex reads. An app without these is not done.
  11. If the app sells, start with a fake checkout until the user gives Stripe test keys, then real Checkout and a signed webhook in convex/http.ts that grants access. Test card 4242 4242 4242 4242, live keys only once the test flow works. See the stripe-checkout skill.
  12. Add a clean error page, a 404 page, a favicon and page titles.
  13. Deploy on Cloudflare. wrangler.jsonc gets main: "@tanstack/react-start/server-entry", compatibility_flags: ["nodejs_compat"], SITE_URL in vars and the custom domain in routes with custom_domain: true. Run npx convex deploy, set prod env vars with npx convex env set --prod, and put the prod VITE_CONVEX_URL / VITE_CONVEX_SITE_URL in the build env. Build and deploy with cf (cf build, cf deploy, or cf cli search "deploy worker"), never by hand in the dashboard; see the cloudflare skill. Deploy from a clean checkout of the pushed commit, never a dirty tree, and always ship both Convex and the Worker. Once the first deploy works, add a GitHub Actions workflow that deploys on every push to main. If the domain is not in the user's Cloudflare account, tell them to move the name servers or buy it there.
  14. Open the live URL and walk the real flows: landing, sign in with a real OTP email, the main action, a list with real rows, a test purchase if the app sells, a keyboard shortcut, sign out, the 404 page. Then the admin: create an admin key in /admin/api-keys, <app> login, <app> whoami, list a resource with --json and compare it with the admin page, make one write through the CLI and see it in Activity, and check that no key or a revoked key gets refused. Check the person shows up in Lumail as subscribed with the right tag. Fix every error you see, then run audit-safety on auth, data access, API keys, admin routes and payments.
  15. Re-read SPEC.md and run every task's Check: on the live URL. Tick a box only once its check passes there, never because the code is written. Do not stop and do not reply while one box is unticked or the live app differs from the spec: fix it, redeploy, check again, and repeat until everything matches. A task blocked only by a human step (a login, a key, a payment) stays unticked with the reason written next to it; finish all the others first.

Secrets go only in .env.local, npx convex env set, Cloudflare secrets or GitHub Actions secrets, never in a committed file, a log or the chat. Reply with what is live, the URL, the admin URL, the CLI command and the /<app>-cli skill their agent can now use (with one sentence to try, like "ask your AI: how many people signed up this week?"), the SPEC.md tasks all ticked, and only the human steps left to do.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.