Small Business Website Spec
⚠️ This is a planning/specification reference, not a deployable skill for
no-code platforms. Base44 and similar builders have no CLI the agent can
call — building there means dragging pages in a web editor, done by a human.
A static framework (Astro/Hugo/Eleventy) on Vercel/Netlify/Cloudflare Pages
is agent-workable: the agent can clone the repo, edit, run checks, and push.
Either way, this skill is the spec: page structure, copy voice, estimator
widget, SEO checklist, form handling, and the DNS cutover runbook.
When to Use
- Planning a website rebuild for a small service business
- Choosing between no-code (Base44, Wix Studio, Squarespace) and a static framework (Astro on Vercel)
- Page structure, copy voice, estimator widget, SEO requirements
- DNS migration notes (registrar → new host)
- Wiring contact-form submissions into the agent (email → IMAP polling → CRM → Telegram)
- NOT for automated no-code deployment — no agent-accessible CLI exists there
Platform Decision: No-Code vs Static Framework
Both paths are valid. Pick by workload, not by hype:
| Factor |
No-code (Base44 etc.) |
Static framework (Astro/Vercel etc.) |
| Who builds it |
Human, in a web editor (drag-and-drop) |
Human or AI coding agent, in a repo |
| Time to first draft |
Hours |
Days |
| Monthly cost |
~$50/mo for domain connection + GitHub sync on Builder-tier plans |
$0 on Vercel/Netlify free tiers (or an existing plan) |
| SEO |
Prerendering exists but is often a black box you can't control |
Static HTML — fully crawlable, you own everything |
| Export/exit |
Frontend only; backend (auth, DB, entities) stays on the platform SDK — you can't self-host by exporting |
It's your repo. Portable by definition. |
| Site types that fit |
Interactive apps, member areas, anything needing a real backend |
Marketing sites: pages + one estimator widget + one contact form |
| Mutability |
A living app on their platform — platform updates can change rendering without you touching anything |
An immutable build artifact on CDN edge — it can't break while untouched |
| Agent's role |
Paying for the subscription (via stripe-link-cli) and writing the spec — not the build |
Full repo work: edit, test, verify, push, deploy |
How to choose: if the site needs user accounts, database writes, or complex
app behavior, no-code (or a real framework with a backend) earns its subscription.
If it's a marketing site — pages, photos, an estimator widget, a contact form —
a static build is cheaper, faster to load, better for SEO, and fully agent-workable.
We started on Base44 (for a hackathon "the agent bought the subscription" beat,
which is what stripe-link-cli is for), then pivoted to Astro-on-Vercel for the
production site because a static marketing site had zero backend needs. The
pivot itself was cheap because the spec (this document) was written before
either build — page inventory, copy voice, estimator logic, and SEO checklist
all carried over unchanged.
Prerequisites
- Domain at a registrar (GoDaddy or similar) — keep DNS there, repoint records
- Static path: git repo, framework (Astro recommended), hosting account (Vercel/Netlify)
- No-code path: builder account, manual signup + build in the web interface
- Form delivery: an email API (Resend/Postmark/SES) or SMTP — forms should email the owner's inbox
- Payment for no-code subscriptions via the
stripe-link-cli skill (agent handles the spend, human handles the build)
Website Architecture
Pages needed (marketing site for a service business)
- Home — hero image, value proposition, primary CTA ("Get Free Estimate"), estimator above the fold
- Service pages — one per service line (built from a template route; each names the reader's exact situation in the first two sentences)
- Service area / location pages — one per market city (template route, real local copy, not doorway spam)
- Realtors & property managers — the B2B repeat-revenue page, if referrals drive the business
- About / Why Us — owner story, process steps, trust signals, real photos
- Gallery — real job photos, captioned
- FAQ — include a "what makes you different from everyone else?" answer
- Contact — form with estimator pre-fill flow
- Reviews — embedded review widget (or hold back until the widget is wired)
- Thank you —
noindex, conversion event fires here
- Terms — warranty/terms as a proper page (not a PDF scan)
- 404, plus
robots.txt, llms.txt (for AI/agentic search), sitemap-index.xml
Estimator tool integration
The estimator is the conversion hook AND the differentiator. Pricing logic
lives in ONE place (see estimator-engine skill; a rate-card.json both the
website widget and the agent read is the cleanest split).
- Input: square footage, region tier, property type (residential/commercial/apartment), add-ons
- Output: a ±15% range, never a single number, never internal line-item math
- Flow: result → one tap → contact form pre-filled with all inputs + quoted range
- Mobile-first: thumb-reachable controls, ≤60 seconds, ≤8 taps
- The website widget, the agent's chat estimator, and the rate-card file
must all read from the same rate card. If a price changes, change the rate
card first; both consumers pick it up. Canonical source:
estimator-engine.
Contact form handler
- Serverless function (or the host's form feature) receives the POST
- Email API (Resend etc.) delivers to the owner's inbox — reply-to set to
the submitter so the owner can hit Reply
- Honeypot spam field (hidden "company" input — if filled, reject silently)
- Validate: required core fields, plus "at least one of phone or email"
- Carrying estimator data into the form? Keep it as structured fields in the
submission email — the agent's inbox monitor parses them (see below)
- Optional webhook to the agent — but see "Lead intake" before exposing one
Lead intake (agent integration)
Two ways to get form submissions to the agent:
A. IMAP polling (recommended default). The form emails the owner's inbox
with a stable subject prefix (New website lead: ...) and a structured
plain-text body. A no_agent=True cron script polls the inbox every 3 min,
parses the fields, logs to CRM, and texts the owner's Telegram. Latency ~3 min
— irrelevant for a few leads a week. No public endpoint, nothing to attack.
Full pattern: grasshopper-voicemail-monitor skill and its notification-email
reference.
B. Webhook (faster, more surface). The form handler POSTs straight to an
agent endpoint. You get instant delivery but you must expose, secure, rate-
limit, and monitor a public URL on the agent box. Only worth it at volume.
Choose A unless leads/minute is a real metric for you. The webhook code can
stay in the form handler, dormant, if you want the option open.
Content guide
Copy voice
- Premium-because-[your real differentiator] — never "affordable,"
"budget-friendly," "cheap" (they attract price-shoppers, not your buyers)
- Lead with the outcome (it works, it's guaranteed, it's permanent) — not the chemistry
- Name the reader's exact situation in the first 2 sentences of every service page
- Specificity = trust: real cities, real timeframes, real guarantee terms
- ~7th-grade reading level, short sentences
Banned-word check
Add a verify-script check for cheap-sounding words: affordable,
budget-friendly, cheap, competitive pricing, "we work with many budgets,"
best-in-class, world-class, "look no further." Ban list lives in the repo and
runs in CI — banned words slip back in with every copy edit otherwise.
Guarantee
If you advertise a guarantee, state its exceptions wherever the guarantee
appears — exceptions buried on a distant page erode trust and invite disputes.
Common Pitfalls
- Contact-form cutover risk: the OLD site's form probably works and goes
to the owner's inbox. Do NOT repoint DNS until the new form is verified
delivering to that same inbox on a staging domain. Breaking a working
lead path is worse than keeping the old site live another week.
- DNS propagation: 24-48h. Save old DNS values for instant rollback.
- Email routing: changing A/CNAME records is fine, but MX records stay
pointed at the email host (e.g. Workspace:
imap.secureserver.net /
smtpout.secureserver.net). Repointing MX silently breaks the business's email.
- Mobile-first: most service-business leads come from phones. Test at
320px, 375px, 414px widths.
- 301 redirects: map old (especially WordPress) URLs → new pages before
cutover, or years of accumulated SEO equity 404s overnight.
- Banned words: enforce via the verify script, not vigilance.
- Terms & conditions: a scanned-image PDF has no extractable text —
transcribe it into a real page.
- Stock photos: verify licensing before a live launch; "we scraped them
from our old site" is not a license.
- Browserless agent box: no-code checkout and Lighthouse audits need a
browser. The agent can't drive a web UI without Chromium
(
npx playwright install --with-deps chromium); run audits via web tools.
- Region classification sync: if you update region tiers in
estimator-engine, update the estimator widget options AND the rate-card
file. All three must match. Canonical source: estimator-engine.
- No-code export is a one-way door: the frontend exports; the backend
doesn't. If you start on no-code, treat it as a prototype — don't wire
business logic (auth, DB, entities) into it that you'll have to rebuild.
- Agent pushes to
main: for a 1-2 person shop, direct-push with a
quality gate (tests + verify script) is faster than PR review. Whatever
you choose, make it a written convention — agents follow conventions,
they don't infer them.
- GitHub PATs expire: if the clone URL embeds a PAT, pushes fail
mysteriously ~30 days later. Check the token's expiry when setting up,
and note the
git remote set-url fix before it bites.
DNS Configuration (registrar → Vercel example)
Type: CNAME
Name: www
Value: cname.vercel-dns.com
Type: A
Name: @
Value: 76.76.21.21 (Vercel default)
(No-code hosts give you their own CNAME/A targets — same idea.)
Do NOT touch MX records — email stays with the email host.
Cutover order:
- New contact form verified delivering to the owner's inbox (staging domain)
- Owner sign-off on content + design
- THEN repoint DNS
- Old DNS values saved for instant rollback
Verification Checklist
Quality gate (automated — run before every push)
Pre-cutover (manual)
Post-cutover
1---2name: small-business-website-spec3description: Planning reference for rebuilding a small business website: page structure, copy voice, estimator widget, SEO requirements, form handling, DNS migration, and the no-code vs static-framework decision (Base44 vs Astro/Vercel vs WordPress). NOT a deploy tool for no-code platforms — no-code builders have no agent-accessible CLI. Includes the honest reasons we pivoted from no-code to a static framework.4license: MIT5---67# Small Business Website Spec89> ⚠️ **This is a planning/specification reference, not a deployable skill for10> no-code platforms.** Base44 and similar builders have no CLI the agent can11> call — building there means dragging pages in a web editor, done by a human.12> A static framework (Astro/Hugo/Eleventy) on Vercel/Netlify/Cloudflare Pages13> *is* agent-workable: the agent can clone the repo, edit, run checks, and push.14> Either way, this skill is the spec: page structure, copy voice, estimator15> widget, SEO checklist, form handling, and the DNS cutover runbook.1617## When to Use18- Planning a website rebuild for a small service business19- Choosing between no-code (Base44, Wix Studio, Squarespace) and a static framework (Astro on Vercel)20- Page structure, copy voice, estimator widget, SEO requirements21- DNS migration notes (registrar → new host)22- Wiring contact-form submissions into the agent (email → IMAP polling → CRM → Telegram)23- NOT for automated no-code deployment — no agent-accessible CLI exists there2425## Platform Decision: No-Code vs Static Framework2627Both paths are valid. Pick by workload, not by hype:2829| Factor | No-code (Base44 etc.) | Static framework (Astro/Vercel etc.) |30|---|---|---|31| Who builds it | Human, in a web editor (drag-and-drop) | Human or AI coding agent, in a repo |32| Time to first draft | Hours | Days |33| Monthly cost | ~$50/mo for domain connection + GitHub sync on Builder-tier plans | $0 on Vercel/Netlify free tiers (or an existing plan) |34| SEO | Prerendering exists but is often a black box you can't control | Static HTML — fully crawlable, you own everything |35| Export/exit | Frontend only; backend (auth, DB, entities) stays on the platform SDK — you can't self-host by exporting | It's your repo. Portable by definition. |36| Site types that fit | Interactive apps, member areas, anything needing a real backend | Marketing sites: pages + one estimator widget + one contact form |37| Mutability | A living app on their platform — platform updates can change rendering without you touching anything | An immutable build artifact on CDN edge — it can't break while untouched |38| Agent's role | Paying for the subscription (via stripe-link-cli) and writing the spec — not the build | Full repo work: edit, test, verify, push, deploy |3940**How to choose:** if the site needs user accounts, database writes, or complex41app behavior, no-code (or a real framework with a backend) earns its subscription.42If it's a marketing site — pages, photos, an estimator widget, a contact form —43a static build is cheaper, faster to load, better for SEO, and fully agent-workable.4445We started on Base44 (for a hackathon "the agent bought the subscription" beat,46which is what `stripe-link-cli` is for), then pivoted to Astro-on-Vercel for the47production site because a static marketing site had zero backend needs. The48pivot itself was cheap **because the spec (this document) was written before49either build** — page inventory, copy voice, estimator logic, and SEO checklist50all carried over unchanged.5152## Prerequisites53- Domain at a registrar (GoDaddy or similar) — keep DNS there, repoint records54- Static path: git repo, framework (Astro recommended), hosting account (Vercel/Netlify)55- No-code path: builder account, manual signup + build in the web interface56- Form delivery: an email API (Resend/Postmark/SES) or SMTP — forms should email the owner's inbox57- Payment for no-code subscriptions via the `stripe-link-cli` skill (agent handles the spend, human handles the build)5859## Website Architecture6061### Pages needed (marketing site for a service business)621. **Home** — hero image, value proposition, primary CTA ("Get Free Estimate"), estimator above the fold632. **Service pages** — one per service line (built from a template route; each names the reader's exact situation in the first two sentences)643. **Service area / location pages** — one per market city (template route, real local copy, not doorway spam)654. **Realtors & property managers** — the B2B repeat-revenue page, if referrals drive the business665. **About / Why Us** — owner story, process steps, trust signals, real photos676. **Gallery** — real job photos, captioned687. **FAQ** — include a "what makes you different from everyone else?" answer698. **Contact** — form with estimator pre-fill flow709. **Reviews** — embedded review widget (or hold back until the widget is wired)7110. **Thank you** — `noindex`, conversion event fires here7211. **Terms** — warranty/terms as a proper page (not a PDF scan)7312. **404**, plus `robots.txt`, `llms.txt` (for AI/agentic search), `sitemap-index.xml`7475### Estimator tool integration76The estimator is the conversion hook AND the differentiator. Pricing logic77lives in ONE place (see `estimator-engine` skill; a `rate-card.json` both the78website widget and the agent read is the cleanest split).79- Input: square footage, region tier, property type (residential/commercial/apartment), add-ons80- Output: a **±15% range, never a single number**, never internal line-item math81- Flow: result → one tap → contact form pre-filled with all inputs + quoted range82- Mobile-first: thumb-reachable controls, ≤60 seconds, ≤8 taps83- **The website widget, the agent's chat estimator, and the rate-card file84 must all read from the same rate card.** If a price changes, change the rate85 card first; both consumers pick it up. Canonical source: `estimator-engine`.8687### Contact form handler88- Serverless function (or the host's form feature) receives the POST89- Email API (Resend etc.) delivers to the **owner's inbox** — reply-to set to90 the submitter so the owner can hit Reply91- Honeypot spam field (hidden "company" input — if filled, reject silently)92- Validate: required core fields, plus "at least one of phone or email"93- Carrying estimator data into the form? Keep it as structured fields in the94 submission email — the agent's inbox monitor parses them (see below)95- Optional webhook to the agent — but see "Lead intake" before exposing one9697### Lead intake (agent integration)98Two ways to get form submissions to the agent:99100**A. IMAP polling (recommended default).** The form emails the owner's inbox101with a stable subject prefix (`New website lead: ...`) and a structured102plain-text body. A `no_agent=True` cron script polls the inbox every 3 min,103parses the fields, logs to CRM, and texts the owner's Telegram. Latency ~3 min104— irrelevant for a few leads a week. No public endpoint, nothing to attack.105Full pattern: `grasshopper-voicemail-monitor` skill and its notification-email106reference.107108**B. Webhook (faster, more surface).** The form handler POSTs straight to an109agent endpoint. You get instant delivery but you must expose, secure, rate-110limit, and monitor a public URL on the agent box. Only worth it at volume.111112Choose A unless leads/minute is a real metric for you. The webhook code can113stay in the form handler, dormant, if you want the option open.114115## Content guide116117### Copy voice118- **Premium-because-[your real differentiator]** — never "affordable,"119 "budget-friendly," "cheap" (they attract price-shoppers, not your buyers)120- Lead with the outcome (it works, it's guaranteed, it's permanent) — not the chemistry121- Name the reader's exact situation in the first 2 sentences of every service page122- Specificity = trust: real cities, real timeframes, real guarantee terms123- ~7th-grade reading level, short sentences124125### Banned-word check126Add a verify-script check for cheap-sounding words: *affordable,127budget-friendly, cheap, competitive pricing, "we work with many budgets,"128best-in-class, world-class, "look no further."* Ban list lives in the repo and129runs in CI — banned words slip back in with every copy edit otherwise.130131### Guarantee132If you advertise a guarantee, state its exceptions wherever the guarantee133appears — exceptions buried on a distant page erode trust and invite disputes.134135## Common Pitfalls136137- **Contact-form cutover risk:** the OLD site's form probably works and goes138 to the owner's inbox. Do NOT repoint DNS until the new form is **verified139 delivering to that same inbox** on a staging domain. Breaking a working140 lead path is worse than keeping the old site live another week.141- **DNS propagation:** 24-48h. Save old DNS values for instant rollback.142- **Email routing:** changing A/CNAME records is fine, but **MX records stay143 pointed at the email host** (e.g. Workspace: `imap.secureserver.net` /144 `smtpout.secureserver.net`). Repointing MX silently breaks the business's email.145- **Mobile-first:** most service-business leads come from phones. Test at146 320px, 375px, 414px widths.147- **301 redirects:** map old (especially WordPress) URLs → new pages before148 cutover, or years of accumulated SEO equity 404s overnight.149- **Banned words:** enforce via the verify script, not vigilance.150- **Terms & conditions:** a scanned-image PDF has no extractable text —151 transcribe it into a real page.152- **Stock photos:** verify licensing before a live launch; "we scraped them153 from our old site" is not a license.154- **Browserless agent box:** no-code checkout and Lighthouse audits need a155 browser. The agent can't drive a web UI without Chromium156 (`npx playwright install --with-deps chromium`); run audits via web tools.157- **Region classification sync:** if you update region tiers in158 `estimator-engine`, update the estimator widget options AND the rate-card159 file. All three must match. Canonical source: `estimator-engine`.160- **No-code export is a one-way door:** the frontend exports; the backend161 doesn't. If you start on no-code, treat it as a prototype — don't wire162 business logic (auth, DB, entities) into it that you'll have to rebuild.163- **Agent pushes to `main`:** for a 1-2 person shop, direct-push with a164 quality gate (tests + verify script) is faster than PR review. Whatever165 you choose, make it a written convention — agents follow conventions,166 they don't infer them.167- **GitHub PATs expire:** if the clone URL embeds a PAT, pushes fail168 mysteriously ~30 days later. Check the token's expiry when setting up,169 and note the `git remote set-url` fix before it bites.170171## DNS Configuration (registrar → Vercel example)172173```174Type: CNAME175Name: www176Value: cname.vercel-dns.com177178Type: A179Name: @180Value: 76.76.21.21 (Vercel default)181```182(No-code hosts give you their own CNAME/A targets — same idea.)183184**Do NOT touch MX records** — email stays with the email host.185186Cutover order:1871. New contact form verified delivering to the owner's inbox (staging domain)1882. Owner sign-off on content + design1893. THEN repoint DNS1904. Old DNS values saved for instant rollback191192## Verification Checklist193194### Quality gate (automated — run before every push)195- [ ] Every page renders static HTML with copy in the raw HTML (no client-only content)196- [ ] Unique title (≤60 chars) + meta description (≤155 chars) per indexable page197- [ ] Exactly one H1 + substantial body copy per page198- [ ] Zero banned words (enforced by script)199- [ ] Estimator output matches the agent's chat estimator (same rate card, test N quotes)200- [ ] Guarantee caveats reachable from every page mentioning "guarantee"201- [ ] Structured data (LocalBusiness, Service, FAQPage) + tap-to-call on every page202- [ ] robots.txt, llms.txt, sitemap-index.xml present; /thank-you is noindex203- [ ] Unit tests pass (pricing engine + form validation)204205### Pre-cutover (manual)206- [ ] Owner sign-off on the site207- [ ] Form submissions verified delivering to the owner's inbox on the real domain208- [ ] Schema.org validates (Google Rich Results Test)209- [ ] Lighthouse mobile: Performance ≥90, SEO ≥95, Accessibility ≥90210- [ ] Real photos on the site (machines/equipment/jobs, not stock)211212### Post-cutover213- [ ] DNS propagated (`dig yourdomain.com`) + HTTPS working214- [ ] 301 redirects from old URLs live215- [ ] Email MX records preserved (don't break email)216- [ ] Search Console + Bing Webmaster verified; sitemap submitted217- [ ] Analytics events firing (estimator_start, estimator_complete, form_submit, call_click)218- [ ] Mobile responsive verified on real devices219- [ ] Lead-intake monitor (if used) picking up form submissions → CRM → Telegram