Copy
Write every word on the marketing site from the PRD. One file holds all landing copy; components pull strings from it. You never write copy ad-hoc inside JSX.
Purpose: turn the spec into on-voice, on-brand homepage strings in one source of truth.
Run: ai_rules/generators/copy_generator.md
Output: ai_rules/app_approach/copy.md
Feeds: the homepage components in app/ and components/ import their strings from it.
Why it exists
Default LLM marketing copy is interchangeable filler. This generator reads your PRD.md and config.ts and writes each block as problem → outcome → proof → single CTA, in a builder's voice, with the humanizer rules enforced. Copy lives in one file so it stays consistent and a rewrite is one edit, not a hunt through JSX.
How to run it
Point the generator at the PRD
It reads PRD.md (primary) and config.ts (names, plan structure, prices). If the PRD is a placeholder, the generator stops and asks you to fill it. It will not invent a product.
Generate each block
Hero, features, how-it-works, pricing, FAQ, final CTA. Each block leads with the reader's problem, states the outcome, backs it with one specific proof, and ends with at most one CTA.
Humanizer pass
Re-read the whole file. Kill the AI-vocabulary words, confirm zero em dashes, vary sentence length, pass the "who wrote this?" test (a specific builder, not anyone).
Save and wire
ai_rules/app_approach/copy.mdWire each block's strings into the matching homepage component. Keep pricing in sync with config.ts.
The code-meet-ai voice
The site speaks as a builder who ships, not a marketing department. These rules override any default "make it punchy" instinct:
- First person, builder voice. Specific over general. Name the stack and the real hour saved.
- Dry, declarative, present tense. Raw over sanded.
- Zero em dashes. Sentence-case headings. Bold sparingly.
- One social-proof number where you have one. Otherwise a
<!-- TODO -->, never a fabricated metric.
Best practices baked in
- One primary CTA per page, the same one in hero and final CTA.
- No number, no claim. Use a TODO instead of a guess.
- Copy is the source of truth. Components import from
copy.md; copy is not scattered across JSX. - Re-run the humanizer after any edit. AI patterns creep back in every time.