Get started
Starting a new product from this template
In the order that keeps everything working at every step. It ends in a gate rather than a "you're done": the last command verifies the rename mechanically and hands you a list of anything missed, with file and line.
Nothing here needs an account, a key or a deploy until step 9.
Throughout: no brand literals. The product's name, domain and URL scheme are spelled in their owner files and nowhere else (root
AGENTS.md§2).scripts/check-brand.shandsite/lib/brand.test.tsenforce it across every language in the repository — they are why step 10 works at all.
1. Rename
scripts/new-app.sh --name "Your App" --domain your-app.com --team ABCDE12345 \
--maker "Your Name" --entity "Your Name or Company" \
--payments creem --deliverable licence-key
With an agent, /new-app asks for these and runs it. After any step here,
scripts/doctor.sh shows where the project is up to and the next step; each
section below turns one of its lines green.
It rewrites the owner files — site/lib/site.ts, site/lib/legal.ts,
mac/App/Core/Brand.swift, mac/project.yml, mac/App/Resources/Info.plist —
records the old names in scripts/brand-ancestors.txt so they can never come
back, deletes the DMG layout (it records the volume name), and runs the brand
check. Options it derives when you leave them out: --scheme (the name,
lower-case, no spaces), --bundle-prefix (the domain reversed), --email
(hello@<domain>).
-
--payments:creem(the default) orpolar. Only the selected adapter is called; the other stays as the worked example. -
--deliverable:licence-keyfor a Mac app,github-inviteto sell access to a private repository (docs/deliverables.md), orboth. Both choices can be changed later withscripts/configure.sh(/switch-paymentsexplains what to do first when customers already have keys). -
--teamis your Apple Team ID (security find-identity -v -p codesigningshows it in brackets). Without it the app signs ad hoc, which is fine for running from Xcode and fatal for a Release build (mac/AGENTS.md). -
The scheme and the bundle identifier are frozen the day the first build ships. Every installed copy keeps its Keychain items under the bundle id and listens for the scheme it shipped with. Choose them now.
2. site/lib/site.ts — the words
The rename set the identity; the copy is yours. Every field has a comment saying what it is load-bearing for — read them rather than pattern-matching.
-
tagline— the one-line promise, under about 60 characters (it is set on the OG card). Name the symptom the buyer has a word for. -
description— two sentences, a claim rather than a category. -
searchDescription— ≤ 155 characters, no price.site/lib/seo.test.tsholds it to that. -
socialDescription— ≤ 120 characters, must not restate the tagline. -
x— the product's own account, or empty if the account that speaks for it is yours (claiming it twice merges you and the product into one entity — seesite/lib/schema.ts). -
MAKER— your site, handle and a real photo insite/public/maker/. The section exists to make the site attributable to a person. -
KEYWORDS,NAV,CTA,FOOTER— check everyhrefstill points at a section or page you kept.
3. site/lib/legal.ts — the seller
-
location,jurisdiction— where you are and whose law governs the terms. The three policy pages read these. -
refundDays— quoted by the FAQ, the pricing card and the refunds page. -
effective— today, asYYYY-MM-DD. Nevernew Date(); bump it in the same commit that changes a policy. - Read
site/app/terms,privacyandrefundsend to end. They are a starting point written from the template's code, not legal advice — and the privacy page must describe what your app sends.
4. What it is, and what it costs
-
site/lib/features.ts— the features, each one something the shipped build actually does (rootAGENTS.md§7). -
site/lib/faqs.tsx— every answer re-read against the Swift. The move- Macs answer quotes Settings labels word for word. -
site/lib/pricing.ts— the ladder (LICENSE_TIERS), which rung isprimary, and the amounts. One rung is a valid ladder. The primary rung must equalLicenseSheet.defaultDevicesinmac/App/Core/LicenseSheet.swift. -
site/lib/launch.ts— leaveonSalefalse untildocs/go-live.mdsays otherwise. -
site/lib/license.ts— the macOS floor must name the same release asdeploymentTargetinmac/project.yml. -
site/lib/changelog.ts— keep one row, and set its date on release day.
5. The look
-
site/public/app-icon.svg— your mark, 1024×1024. Then, from the root:```bash swift scripts/make-icons.swift ``` which writes the favicons, the touch icon and the Mac app's icon set from that one drawing. `mac/AppTests/AppIconTests.swift` fails if you forget. -
Colours:
site/app/globals.css(the:rootblock and thelight-dark()pairs),site/lib/palette.ts, andmac/App/App/Palette.swift— three files, one edit.site/lib/palette.test.tsnames the file and token out of step, measures contrast, andmac/scripts/check-palette.shwelds the app. A dark-only product:docs/modules/theme.md. -
Optionally
swift mac/scripts/make-dmg-background.swiftafter a palette change; it reads the dark tokens.
6. The app
- Replace
mac/App/Screens/HomeView.swiftwith your product. Logic goes inmac/App/Core/with tests (mac/AGENTS.md); screens take values and required closures. - A menubar product instead of a window:
docs/modules/menubar.md. -
mac/App/Resources/App.entitlements— add only what a feature needs, and say which feature, in the file.
7. The plan
-
docs/PRD.template.md→docs/PRD.md, filled in, then frozen. -
wiki/— replace the placeholders; keepR1 Licence Gateas the model for your own requirements.
8. Deleting what this product will never need
Most of what ships is scaffolding for something a product may never do, and
deleting it is expected. After each deletion, scripts/verify.sh --quick — if
it passes, the deletion was complete.
- No analytics —
docs/modules/analytics.mdlists every file in the chain. - No tiers — delete two rows of
LICENSE_TIERS; the switch disappears. - No waitlist — keep it; with
onSaletrue it is not rendered, and the day you want to pause sales it is one boolean away.
What must survive every deletion: site/lib/site.ts, seo.ts, schema.ts,
palette.ts and their tests, and every route named in mac/App/Core/Brand.swift
— shipped binaries call those forever.
9. Hosting
-
cd site && cp .env.example .env.local, fill in nothing, and confirmpnpm devworks. That is the degradation contract, worth seeing once with your own name on the page. - Create the Vercel project with Root Directory
siteand build commandpnpm run vercel-build(the site-URL gate runs beforenext build). - Set
NEXT_PUBLIC_SITE_URLon Production:https://and the apex host, nowww. The one variable a production build refuses to go without. - Push to GitHub.
.github/workflows/ci.ymlruns on every push.
10. The gate
scripts/verify.sh
Every offline check: the brand across the repository (the list of anything the rename missed), the docs, the welds between app and site, both test suites, both builds, and a launch of the app on every architecture this Mac can run.
Then, against a production build of the site:
cd site && pnpm build && pnpm start
./scripts/assert-metadata.sh http://localhost:3000
It fetches every page and asserts the indexing contract — one canonical per
page, naming itself; descriptions; JSON-LD that parses; robots, sitemap,
llms.txt, feed. Run it again against the deployed site.
What comes next
- Taking money:
docs/go-live.md. - Shipping the app:
docs/releasing.md. - Growing past the first release:
docs/growing.md. - The conventions that keep all of this true:
AGENTS.md.
This page is docs/new-project.md in the repository, copied 2026-09-25.