Activation Prompt
You are in Landing Pages mode. Before starting any build, read docs/website-landing-page-ghl-external-hosting-sop.md in full. Core rules: build HTML/CSS externally (Cloudflare Pages or client domain), GHL handles CRM/forms/automations only. Identify the page type (Type 1 campaign, Type 2 website rebuild, Type 3 SEO treatment page) before writing a single line of code. Follow the QA checklist and compliance rules in Sections 6 and 14 before showing anything to the client.
Aurea Growth SOP — Building Websites & Landing Pages with Codex/Claude Code, GHL Logic, and External Hosting
Last updated: 2026-05-13 (revised 2026-05-15: added smart-quote HTML attribute bug to Section 7 and Technical QA; revised 2026-05-13: added GHL iframe performance/reliability pattern, Cloudflare cache headers, robots.txt note, GHL custom code production pattern with absolute URLs, CTA/form tracking hook pattern, mobile sticky CTA note, expanded skill stack and best-practice invocation order)
Use this SOP whenever Aurea Growth builds a client website, paid-search landing page, or campaign page with Codex/Claude Code while using GoHighLevel for CRM, forms, automations, calendars, and follow-up.
Core principle: do not let GHL page-builder limitations force the page to look cheap. Use the best front-end build for the visitor and the best GHL logic for the backend.
0. Page Type Classification
Identify which type you are building before starting. Different rules apply.
Type 1 — Campaign / Paid-Search Landing Page
- Single treatment or offer.
- Single primary CTA.
- Strict qualification gate before calendar access.
- Free consultation as the offer.
- GHL handles CRM, tags, automations, calendar, follow-up.
- Hosted on client domain at a treatment-specific URL.
- Optimised for Google Ads Quality Score.
- Does not need ongoing CMS management — it is a campaign asset.
Type 2 — Website Rebuild / Redesign
- Full homepage plus existing treatment pages.
- Softer CTA — consultation enquiry or WhatsApp, not a strict suitability gate.
- SEO preservation is a hard constraint — existing URLs, Rank Math scores, and indexed pages cannot be thrown away without a redirect plan.
- Ongoing CMS management required — migrate to Framer after Claude Code locks the design, or use a WordPress theme that a non-developer can edit.
- GHL form is lighter — name, concern, contact — not a 6-step qualification gate.
- Automation is often already in place via the clinic's existing GHL account.
Type 3 — SEO Treatment Page
- A single page targeting one treatment keyword for organic search.
- Not driven by ad spend, so Google Ads Quality Score is not the main concern.
- Long-form copy, FAQ schema, local intent, internal links to homepage and related pages.
- Usually part of a website rebuild, not a standalone build.
- Can be built in WordPress natively or as a standalone HTML page added to an existing site.
Choose the type before opening a file. The structure, CTA logic, form type, and hosting decision all follow from this.
1. Default Recommendation
Best Production Setup
Ad / Search / Campaign Traffic
→ Client domain landing page
→ Custom HTML/CSS built with Codex or Claude Code
→ GHL-powered form / external form tracking
→ GHL calendar or conditional thank-you page
→ GHL workflows, tags, pipeline, tasks
→ GA4 + Google Ads conversion tracking
Why This Is The Default
- Best for Google Ads Quality Score: page lives on the client domain, with a relevant URL, fast load, strong content match, and trust signals.
- Best for trust: patients see the real clinic domain, not a generic funnel URL.
- Best for design quality: Codex/Claude Code can build a premium page without fighting GHL layout constraints.
- Best for backend operations: GHL still handles CRM, tagging, automations, internal tasks, calendar, SMS/email follow-up, and reporting.
QS vs Attribution — Important Distinction
When pitching the move from GHL subdomain to main client domain, be precise about what actually improves.
Quality Score improves from:
- Better page content relevance to the keyword (this is the main lever)
- Faster page load speed
- Cleaner design and user experience
- Not from the domain change alone
Attribution improves from:
- Having the landing page and thank-you step on the same domain as the ad click (eliminates the cross-domain referral break in GA4)
- Keeping the session alive through form submission without handing off to api.leadconnectorhq.com or page-builder.leadconnectorhq.com as a referral source
- Means Google Ads sees more conversions attributed to google / cpc instead of (direct) or GHL referral
The domain move helps most on attribution. Page content, copy relevance, and load speed help most on QS. Both are worth doing together. Do not over-claim the QS benefit when pitching the domain move — "better page + faster load = better QS" is correct. "Moving to the main domain alone fixes QS" is not.
2. Decision Tree
Option A — Custom Page On Client Domain + GHL Logic
Use this when:
- We have WordPress, SiteGround, Webflow, Wix, Framer, Cloudflare, or server access.
- The page needs to look premium.
- Google Ads Quality Score matters.
- The offer is high-ticket, medical/aesthetic, dental, or trust-sensitive.
- The client already has domain authority or a known clinic website.
Recommended for:
- Google Ads landing pages
- SEO-ready treatment pages
- Premium clinic offers
- High-ticket consultation funnels
- Pages the client may inspect closely
Option B — GHL Page/Funnel Built Natively
Use this when:
- Website/domain access is delayed.
- The page must be live immediately.
- The form/calendar/workflow logic is more important than perfect design.
- The page is for internal testing or a fast pilot fallback.
Recommended for:
- Temporary pilot pages
- Quick MVP funnels
- Fallback before a client meeting
- Simple lead capture pages where design stakes are lower
Option C — Full Custom HTML Pasted Into GHL Custom Code
Primary use: visual testing, fast internal preview, showing the concept to the team.
Also validated as a temporary production approach when DNS/subdomain access is blocked and the existing GHL URL must stay untouched. This keeps the same final URL, the same post-form GHL logic, and avoids any DNS complexity or CNAME negotiation with the client.
Required fixes before pasting into GHL:
- Replace all relative
assets/paths with absolute Cloudflare Pages URLs — GHL has no local file context so relative paths silently fail. Catchsrc=,href=,srcset=,imagesrcset=, and comma-separated srcset values —srcsetis easy to miss and will break the hero image.
sed \
-e 's|href="assets/|href="https://your-project.pages.dev/assets/|g' \
-e 's|src="assets/|src="https://your-project.pages.dev/assets/|g' \
-e 's|srcset="assets/|srcset="https://your-project.pages.dev/assets/|g' \
-e 's|imagesrcset="assets/|imagesrcset="https://your-project.pages.dev/assets/|g' \
-e 's|, assets/|, https://your-project.pages.dev/assets/|g' \
index.html | pbcopy
- Add a GHL width escape to the outermost page div. GHL wraps pasted code in a constrained container. Without this the page renders narrower than intended:
.page {
position: relative;
width: 100vw;
left: 50%;
transform: translateX(-50%);
}
Permanent limitations of Option C (still apply even for production use):
- Not editable section-by-section in GHL — copy/image changes require re-pasting the full HTML.
- GHL adds a small script/wrapper overhead on top of the page.
- PageSpeed score will be slightly lower than a pure Cloudflare-hosted version.
- Not suitable if Camille or the client needs to make copy edits without John.
3. GHL Form Strategy
Best Form Strategy On GHL Pages
Use native GHL forms or surveys.
Benefits:
- Clean CRM capture.
- Native custom fields.
- Tags and workflow triggers work predictably.
- Conditional logic/disqualification can be configured inside GHL.
- Calendar routing is easier.
Best Form Strategy On External Pages
Prefer a DOM-compatible form that GHL can track through External Form Tracking.
Requirements:
- The form exists directly in the page DOM.
- It uses a real
<form>element. - Inputs have valid
nameattributes. - The form can be mapped into GHL fields.
- Success/thank-you states can be tracked for Google Ads conversions.
Iframe Form Embeds
The standard GHL embed often looks like this:
<iframe
src="https://api.leadconnectorhq.com/widget/form/FORM_ID"
style="width:100%;height:100%;border:none;border-radius:1px"
id="inline-FORM_ID"
data-layout="{'id':'INLINE'}"
data-trigger-type="alwaysShow"
data-form-name="Clinic Assessment Form"
data-height="1437"
data-form-id="FORM_ID"
title="Clinic Assessment Form">
</iframe>
<script src="https://link.msgsndr.com/js/form_embed.js"></script>
This is acceptable for quick embedding, but it is not the ideal tracking-critical setup.
Use iframe embeds when:
- Speed matters more than perfect external tracking.
- The form is simple.
- We are using GHL-native submission data and not relying on DOM-level external form tracking.
- We can still fire conversions from a thank-you page or redirect.
Avoid iframe embeds when:
- We need precise external form tracking.
- We need custom JavaScript to inspect field-level answers.
- We need maximum Google Ads conversion clarity.
- The form sits inside a custom page and must behave like a native component.
Embed Test Learning — Ayadi 2026-05-11
When testing GHL form embeds inside a custom HTML page:
- Test through
https://, notfile://. GHL embed scripts may not behave correctly from a local file. - Cloudflare Pages is a good temporary HTTPS preview environment.
- The GHL
POLITE_SLIDE_INembed is designed to appear as a slide-in overlay. It may render as blank/hidden inside a normal page section because its iframe often starts withdisplay:noneand waits for the GHL script to reveal it. - For a form that should sit inside the landing page's assessment section, use the
INLINEembed mode. - If two test URLs look identical after converting both to
INLINE, that is expected. The original slide-in version has effectively been changed into the same inline form experience. - If replacing a custom/native form with a GHL iframe, remove or guard any JavaScript that expects the old form elements to exist. Otherwise page scripts can crash before scroll-reveal or layout JavaScript runs, making the page look empty between header and footer.
Safe JavaScript pattern:
const form = document.getElementById("suitabilityForm");
const nextBtn = document.getElementById("nextBtn");
function initNativeSuitabilityForm() {
if (!form || !nextBtn) return;
// Native form logic here.
}
function initReveal() {
document.querySelectorAll(".reveal").forEach((element) => {
element.classList.add("in");
});
}
initReveal();
initNativeSuitabilityForm();
Production note: for the final client domain version, the inline iframe embed can be acceptable if speed matters and conversion tracking is handled on the thank-you/redirect step. For maximum external tracking visibility, use a DOM-native form with GHL External Form Tracking or webhook submission instead of iframe.
GHL Iframe Performance Pattern — Nurse Kelsey 2026-05-13
GHL iframe embeds can behave like a performance trap on custom landing pages.
What happened:
- A custom Cloudflare landing page scored around
90on mobile when the GHL form was not loaded initially. - Loading the GHL iframe immediately made the form visible, but dropped mobile performance to around
59. - The iframe pulled in the LeadConnector/GHL stack, including third-party JavaScript, Facebook resources, phone-number libraries and extra main-thread work.
- Over-optimising the form with generic lazy loading / reveal animations /
content-visibilitycaused the form to disappear or render unreliably.
Recommended pattern for campaign pages:
<iframe
data-src="https://api.leadconnectorhq.com/widget/form/FORM_ID"
style="width:100%;height:1019px;border:none;display:block;"
id="inline-FORM_ID"
data-layout="{'id':'INLINE'}"
data-form-id="FORM_ID"
title="Clinic Assessment Form">
</iframe>
const ghlFrame = document.getElementById("inline-FORM_ID");
function loadGhlForm() {
if (!ghlFrame || ghlFrame.src) return;
ghlFrame.src = ghlFrame.dataset.src;
}
if (ghlFrame) {
if (window.location.hash === "#assessment") {
loadGhlForm();
} else if ("IntersectionObserver" in window) {
const formObserver = new IntersectionObserver((entries) => {
if (entries.some(entry => entry.isIntersecting)) {
loadGhlForm();
formObserver.disconnect();
}
}, { rootMargin: "900px 0px" });
formObserver.observe(ghlFrame);
} else {
loadGhlForm();
}
document.querySelectorAll('a[href="#assessment"]').forEach(link => {
link.addEventListener("click", loadGhlForm, { once: true });
});
}
Rules:
- Do not put reveal animation classes on the form card or form iframe container.
- Do not use
content-visibilityon the section containing a GHL iframe. - Avoid
loading="lazy"on a GHL iframe if the form fails to render reliably. - Prefer intent-based loading: load when the user opens
#assessment, clicks a CTA, or scrolls near the form. - When the iframe is intent-loaded, push a lightweight analytics event at the exact moment
srcis assigned. GTM/GA4 can then track "form became available" even if the form itself lives inside LeadConnector and cannot be inspected from the parent page. - If using GHL's
form_embed.js, test carefully. A plain iframe can be more reliable if the height is fixed and the form displays correctly. - Expect PageSpeed to penalise immediate GHL iframe loading. This is not necessarily a page-design issue; it is the third-party form stack.
Use this pattern only when an iframe is acceptable. If attribution and field-level visibility are business-critical, build a DOM-native form and submit to GHL instead.
Optional tracking hook pattern for external pages:
window.dataLayer = window.dataLayer || [];
function trackEvent(eventName, properties = {}) {
window.dataLayer.push({
event: eventName,
page_type: "treatment_assessment_landing_page",
...properties
});
if (typeof window.gtag === "function") {
window.gtag("event", eventName, properties);
}
}
document.querySelectorAll("[data-track-cta]").forEach(link => {
link.addEventListener("click", () => {
trackEvent("cta_clicked", {
cta_location: link.dataset.trackCta,
cta_text: link.dataset.trackLabel || link.textContent.trim()
});
});
});
function loadGhlForm() {
if (!ghlFrame || ghlFrame.src) return;
ghlFrame.src = ghlFrame.dataset.src;
trackEvent("assessment_form_loaded", {
form_id: ghlFrame.dataset.formId,
form_location: "assessment_section"
});
}
This does not replace real GA4/GTM setup. It gives GTM a clean dataLayer event contract once the container is added, and it still works harmlessly if gtag is not present.
4. Recommended Build Workflow With Codex / Claude Code
Step 1 — Gather Client Context
Read the client/prospect file first.
Minimum inputs:
- Client name, domain, address, phone.
- Treatment/service focus.
- Offer and price anchor.
- Primary audience.
- Top objections.
- Proof points.
- Booking system.
- GHL sub-account status.
- Access owner.
- Existing website/brand style.
- Required assets.
- Tracking state: GA4, Google Tag, GTM, Google Ads.
For Google Ads, also define:
- Primary keyword group.
- Secondary keyword group.
- Negative keyword themes.
- Campaign goal.
- Conversion event.
- Budget.
- Landing page URL.
Step 2 — Choose The Build Path
Use this hierarchy:
- Client domain custom page if access exists.
- Client domain custom page prepared locally if access is expected soon.
- GHL native page fallback if access is blocked.
- Full custom HTML pasted into GHL only for temporary preview/testing.
Step 3 — Build The Page As A Source Of Truth
With Codex/Claude Code:
- Create a local folder under the relevant client/prospect folder or
tools/. - Build
index.html. - Keep assets in
/assets. - Use real images where possible.
- Compress images.
- Use patient/customer-facing copy only.
- Avoid internal language such as:
- "Quality Score"
- "lead quality"
- "campaign"
- "filter"
- "GHL"
- "Vagaro"
- "Google"
- "client diary"
- Any reference to the client by first name in an operational context
- Any reference to your team member or VA by name
Important: the page must read like the end customer will see it, not like an internal setup guide.
Step 4 — Landing Page Structure
Use this structure for most paid-search clinic campaigns:
- Hero
- Treatment/service keyword in H1.
- Location in H1 or subhead.
- Clear outcome.
- One CTA.
-
Real image or clinic/device visual.
-
Trust strip
- Years of experience.
- Location.
- Founder-led / clinician-led care.
- Technology/device proof.
-
Review or rating if available.
-
Problem / fit
- Who this is for.
- What concerns it helps with.
-
Avoid insecurity-led copy.
-
Benefits
- 3-5 outcome-driven blocks.
-
Keep claims careful and compliant.
-
Treatment/service explanation
- What it is.
- How it works.
- What happens during consultation.
-
Why a course/plan may be needed.
-
Why this clinic
- Local differentiation.
- Founder/clinician experience.
- Environment.
-
Proof.
-
Form / suitability check
- Short enough to complete.
- Strict enough to protect client time.
- One question per step if multi-step.
-
On long mobile pages, keep a restrained sticky CTA visible after the first screen so users do not need to scroll thousands of pixels back to the form. It should use the same primary CTA, be hidden on tablet/desktop, respect safe-area insets, and never cover footer content.
-
FAQ
- Handle objections before final CTA.
-
Include timeline, price, suitability, pain, downtime, what happens next.
-
Final CTA
- Same primary CTA.
- Clear next step.
- Address/location.
Step 5 — Copy Rules
Every visible word must be customer-facing.
Use:
- "Request an assessment"
- "Check suitability"
- "Choose a consultation time"
- "Your clinician will explain..."
- "A full course can require..."
- "This helps keep the consultation transparent..."
Avoid:
- "Lead"
- "Filter"
- "Disqualify"
- "Pipeline"
- "Workflow"
- "GHL"
- "Quality Score"
- "Google will learn"
- "We train Google"
- "Protect the client's time"
- "This campaign..."
Step 6 — Form Logic
For high-ticket free consultation funnels, use qualification questions that map to routing.
Example:
1. What are you looking to improve?
2. When would you like to start?
3. Are you open to a course-based plan?
4. Is the likely investment within range?
5. Can you attend the clinic location?
6. Name, phone, email
Routing:
- Suitable answer path → calendar / consultation booking.
- Not suitable answer path → polite thank-you page without calendar.
- Qualified but no booking → GHL task + call/message follow-up.
- Booked in GHL → manual or automated sync into clinic diary if needed.
Step 7 — Calendar / Booking Logic
Choose one source of truth for patient-facing reminders.
Recommended:
- GHL handles form, qualification, calendar booking, internal tasks, non-booker follow-up.
- Clinic booking system handles official appointment confirmation/reminders once duplicated or synced.
Avoid duplicate reminders from both systems unless intentionally configured.
For manual sync:
GHL booking created
→ Internal task assigned
→ Team duplicates appointment into clinic booking system
→ Clinic system sends official confirmation/reminder
Step 8 — Tracking Plan
Minimum tracking:
- GA4 page_view on landing page.
- Google Ads click ID capture where possible.
- Conversion event for suitable form submission.
- Conversion event for booked consultation.
- Thank-you page or success state that can be tracked.
- GHL source fields: campaign, keyword, ad group, GCLID, landing page URL, form answers.
For Google Ads:
- Primary conversion: suitable assessment request or booked consultation.
- Secondary conversion: form start, form complete, calendar view.
- Do not optimise to raw page views or low-quality submissions.
Step 9 — Hosting
WordPress / SiteGround
Best when the client site is WordPress.
Implementation options:
- Create a custom page template.
- Use a lightweight custom HTML block if theme allows.
- Use Elementor only if needed, but avoid bloated widgets.
- Upload assets to WordPress media library.
- Add page-specific CSS/JS if supported.
Recommended URL format:
https://clientdomain.com/treatment-name-location/
https://clientdomain.com/treatment-name-assessment/
WordPress + ACF pattern (recommended for campaign pages that need ongoing copy management):
Use Advanced Custom Fields (ACF) to separate design from content. Build the page template in code once, expose only the editable text fields and images as ACF fields in the WordPress admin. The VA or client edits copy through a simple form in WP admin with no HTML exposure. The design and layout are locked.
When to use this pattern:
- The page needs to look premium (full code control) but the VA or client needs to update headline, body copy, or photos without touching HTML.
- The alternative would be training a VA on Claude Code just to edit a landing page.
- The client is on WordPress and Elementor would compromise design quality.
What to expose as ACF fields (typical campaign page):
- Hero headline
- Hero subheadline / lede
- CTA button text
- Stat strip (4 stats: number + label)
- Section headlines
- Body paragraphs
- Hero image, founder image, treatment/clinic images
- FAQ questions and answers
What to lock in the template (never editable via ACF):
- Layout, grid, spacing
- Typography scale and fonts
- Colour palette
- Section order
- Button styles
- Scroll reveal logic
Cloudflare Pages
Use when:
- Client domain access is not ready.
- We need a fast temporary preview.
- We need to host a guide or internal client-facing planning doc.
- Sharing a v2 mockup with a client before committing to full implementation.
For live ads, prefer client domain/subdomain over Aurea-owned domains.
Cloudflare preview note:
- Deploy the whole project folder, including
index.html, test pages, and/assets. - Use the root
https://project.pages.devURL if the hashed preview URL has temporary SSL issues immediately after deploy. - Hash preview URLs and root Pages URLs may cache differently; after fixes, redeploy and test the root URL first.
- Add a valid
robots.txtfile. Otherwise Cloudflare Pages may return the HTML page for/robots.txt, causing Lighthouse/SEO audits to report a malformed robots file. - Add a
_headersfile for long-lived static asset caching:
/assets/*
Cache-Control: public, max-age=31536000, immutable
/*
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
- Keep
_headersconservative. Avoid adding broadLink: <...>; rel=preconnectheaders unless needed, because duplicate/unused preconnects can hurt Lighthouse diagnostics.
Cloudflare Pages deploy gotcha — project must exist before deploying:
wrangler pages deploy with --project-name will fail with "Project not found" if the project does not already exist. wrangler pages project create can also fail with a generic API error (code 8000000) for unclear reasons.
Workaround: create the project directly via the Cloudflare API, then deploy normally.
ACCOUNT_ID="your-account-id"
TOKEN="your-oauth-token-from-~/.wrangler/config/default.toml"
curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/pages/projects" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"project-name","production_branch":"main"}'
After that succeeds, deploy normally:
wrangler pages deploy ./folder --project-name project-name --branch main
The account ID is visible in wrangler whoami. The OAuth token is in ~/Library/Preferences/.wrangler/config/default.toml (macOS).
Framer
Use for website rebuilds where the client or a non-developer needs to manage content after launch.
- Claude Code / Codex locks the design and page structure.
- Migrate the final design to Framer for CMS-level editing (text, images, pages).
- Framer handles hosting, CDN, and SSL automatically.
- GHL still handles forms, CRM, automations, and calendar — same as any other setup.
- Connect GHL form via JS embed or use a Framer form that posts to a GHL webhook.
Do not use Framer for campaign landing pages where Google Ads Quality Score or custom tracking logic is critical. Use WordPress or a static HTML page for those.
GHL
Use when:
- External hosting access is blocked.
- Speed to launch matters.
- Native form logic is the main priority.
Build natively in GHL, section-by-section. Do not paste the whole page into one code block for production.
5. GHL Native Fallback Build Process
If building in GHL:
- Create a new funnel/page in the client sub-account.
- Rebuild sections with native rows, columns, headings, images, buttons.
- Put global CSS in page custom CSS/header settings.
- Use GHL native form or survey.
- Configure conditional logic:
- Good fit → calendar.
- Poor fit → polite thank-you page.
- Add tags:
- Campaign name.
- Suitable.
- Not suitable.
- Booked.
- No booking.
- Follow-up required.
- Add hidden fields:
- UTM source.
- UTM medium.
- UTM campaign.
- UTM term.
- UTM content.
- GCLID if available.
- Landing page URL.
- Test workflow triggers.
- Test mobile layout.
- Test form → contact → tags → pipeline → calendar → reminders.
6. QA Checklist Before Showing Client
Copy QA
- [ ] No internal terms visible.
- [ ] H1 matches search intent.
- [ ] Location is visible above the fold.
- [ ] CTA is clear and repeated.
- [ ] Price/investment expectation is transparent if needed.
- [ ] Claims are careful and compliant.
- [ ] FAQ answers real objections.
Design QA
- [ ] Looks like the client brand.
- [ ] Does not look like a cheap funnel template.
- [ ] Uses real clinic/device/team assets where possible.
- [ ] Mobile layout is clean.
- [ ] Buttons are tappable.
- [ ] No text overlap.
- [ ] No oversized desktop-only typography breaking mobile.
Technical QA
- [ ] No smart/curly quotes (
",",',') inside HTML tag attributes — rungrep -Pn '[\x{201C}\x{201D}\x{2018}\x{2019}]' index.htmlbefore QA. Smart quotes inclass=,href=,src=etc. silently break CSS matching and look identical to straight quotes in most editors. Browser assigns no class, styles never apply. (Diagnosed on Dr A Winter site, May 2026.) - [ ] Page loads on target URL.
- [ ] Images load from real hosted URLs, not local paths.
- [ ] No base64 production images unless unavoidable.
- [ ] Form submits.
- [ ] Suitable path works.
- [ ] Unsuitable path works.
- [ ] Calendar works.
- [ ] GHL contact is created/updated.
- [ ] Tags apply correctly.
- [ ] Pipeline stage updates.
- [ ] Internal task fires where needed.
- [ ] GA4 sees page view.
- [ ] Google Ads conversion fires on correct event.
- [ ] Privacy policy link works.
7. Common Mistakes To Avoid
- Smart/curly quotes (
",") inside HTML attributes — the Edit tool can introduce these silently. The browser treats the attribute value as including the quote characters literally, soclass="review-card"never matches.review-cardin CSS. Content renders as unstyled plain text with no error shown. Scan for them before debugging cascade or specificity. Run:grep -Pn '[\x{201C}\x{201D}]' index.html - Pasting the entire custom page into one GHL custom HTML block and expecting it to be editable.
- Pasting into GHL with relative
assets/paths — images will silently fail. Always replace with absolute Cloudflare URLs first (see Option C sed command). Do not forgetsrcset=andimagesrcset=attributes —src=alone is not enough. - Forgetting the GHL width escape CSS on
.page— the page renders narrower than the design without it. - Building a premium page visually but leaving internal setup copy visible.
- Using GHL iframe embeds and assuming external form tracking has full field visibility.
- Sending all form submissions to Google Ads as conversions, including low-fit leads.
- Using discount language for premium/high-ticket clinic offers.
- Letting two systems send appointment reminders.
- Hosting a paid-search page on an unrelated Aurea domain when the client domain is available.
- Forgetting privacy policy, address, business identity, and contact details.
- Waiting for perfect automation before launching a manual-sync pilot.
8. Handoff To Builder / VA
When handing to a builder or VA, include:
- Client file path.
- Final page URL target.
- Local mockup path.
- Assets folder.
- Page structure.
- Form questions.
- Routing logic.
- Tags/custom fields.
- Workflow list.
- Calendar link.
- Reminder ownership.
- Tracking events.
- Launch checklist.
Template:
Client:
Page purpose:
Target URL:
Local mockup:
Assets:
Primary CTA:
Form type:
Qualified path:
Not suitable path:
Calendar:
Booking system:
Reminder owner:
GHL tags:
Custom fields:
Tracking events:
Open access needed:
Client review date:
9. Design Standards
Master Skill
For future client landing-page builds, use the Codex skill:
client-landing-page-builder
Use it when John gives a client/prospect name and asks for a landing page, campaign page, website demo, GHL form test, or externally hosted client-domain page. The skill is located at:
/Users/johntossou/.codex/skills/client-landing-page-builder/SKILL.md
It is the orchestration layer for this SOP. It should read the client file, gather local assets, inspect/scrape the website where appropriate, use the relevant design/conversion skills, decide GHL vs external hosting, build the page, add form logic, test via HTTPS, and return the preview path/URL plus open items.
Skills To Invoke
Invoke skills by phase. Do not build from scratch without loading the relevant framework first.
Use the full stack for paid traffic, premium clinic offers, externally hosted pages, or any page that will be sent to a client. Use a lighter stack only for internal mockups, wireframes, or quick one-hour tests.
Phase 1 — Plan (before writing any code)
| Task | Skill |
|---|---|
| Orchestrate the whole client landing-page workflow | /client-landing-page-builder |
| Define page structure and conversion logic | /landing-page |
| Establish design system — colour palettes, font pairings, UX patterns | /ui-ux-pro-max |
| Positioning context for repeat clients or multi-page builds | /product-marketing-context |
| Customer language, review mining, objections, and decision triggers | /customer-research |
Phase 2 — Build (while writing HTML/CSS)
| Task | Skill |
|---|---|
| Aesthetic guardrails — what to do and what never to do | /impeccable |
| Premium/luxury visual direction and agency-level restraint | /high-end-visual-design |
| Taste pass for less template-like frontend execution | /design-taste-frontend |
| Copy and value proposition | /copywriting |
| Edit existing copy for clarity, concision, and premium tone | /copy-editing |
| Conversion psychology — framing, anchoring, social proof, objection handling | /marketing-psychology |
| Page-level CRO — offer, proof, objections, CTA hierarchy, section order | /page-cro |
| Pricing/course framing, value anchoring, deposits, packages | /pricing-strategy |
Phase 3 — Refine (after first draft exists)
| Task | Skill |
|---|---|
| Typography — scale, pairing, leading, optical corrections | /typeset |
| Spacing and visual rhythm — fix monotonous grids, weak hierarchy | /layout |
| Remove excess cards, claims, badges, or noisy complexity | /distill |
| Tone down pages that feel too salesy, loud, or synthetic | /quieter |
| UX microcopy, form labels, reassurance copy, and unclear instructions | /clarify |
| Motion — purposeful entrances, hover states, micro-interactions | /animate |
| Colour — add warmth or expressiveness if design feels flat | /colorize |
| Shadows — polished elevation on cards and panels (Tailwind projects) | /beautiful-shadows |
| Tasteful brand moments where appropriate | /delight |
For premium aesthetic/medical pages, prefer /distill, /quieter, /typeset, and /layout before reaching for louder visual skills. /bolder, /delight, and /overdrive are optional, not default. Use them only when the brand or brief can carry them.
Phase 4 — QA (before client review)
| Task | Skill |
|---|---|
| Form friction, field order, qualification logic, reassurance, embed behaviour | /form-cro |
| Metadata, headings, crawlability, local SEO, and Quality Score support | /seo-audit |
| Structured data — local business, service, FAQ, offer where relevant | /schema-markup |
| AI search/entity optimisation for authoritative treatment pages | /ai-seo |
| Events, GA4/GTM contracts, CTA clicks, form load, submission, thank-you conversion | /analytics-tracking |
| UX audit — visual hierarchy, cognitive load, anti-pattern detection | /critique |
| Responsive / mobile pass — breakpoints, touch targets, fluid layout | /adapt |
| Performance — image weight, lazy third-party embeds, animation cost | /optimize |
| Technical QA — accessibility, contrast, errors, responsive checks | /audit |
Phase 5 — Finish
| Task | Skill |
|---|---|
| Final polish — micro-details, consistency, last-mile quality | /polish |
| Intentional A/B test plan for traffic-backed iterations | /ab-test-setup |
| Cloudflare deploy and Pages/Workers checks | /cloudflare:wrangler |
| Browser inspection of local/live page, CTA clicks, mobile states | /browser-use:browser |
Minimum for every client-facing build: /client-landing-page-builder + /landing-page + /ui-ux-pro-max + /impeccable + /copywriting + /marketing-psychology + /page-cro in Phase 1–2, then /form-cro + /seo-audit + /analytics-tracking + /critique + /adapt + /optimize before sending to client.
Premium/luxury clinic stack: add /high-end-visual-design, /design-taste-frontend, /typeset, /layout, /distill, /quieter, /clarify, and /polish. The desired feeling is expensive, calm, clinically credible, and easy to act on — not decorative, glossy, or over-animated.
Documentation best practice: when a page ships, record the skills used, deploy URL, tracking hooks, GHL form/calendar IDs, and open test items in the project notes or handoff. This prevents the next pass from guessing which quality layers were already applied.
Key distinction — /impeccable vs /ui-ux-pro-max: /impeccable is philosophy and guardrails (what never to do, banned CSS patterns, font reject list). /ui-ux-pro-max is the reference catalogue (161 colour palettes, 57 font pairings, 99 UX guidelines, 50+ styles). Use both together — one sets the rules, the other gives you the options.
Font Selection
Do not use fonts from the impeccable skill reject list. Key banned fonts include: Cormorant Garamond, Playfair Display, Fraunces, DM Sans, DM Serif Display, Inter, Plus Jakarta Sans, Instrument Sans, Instrument Serif, Space Grotesk, Syne, IBM Plex Sans, Lora, Crimson Pro, Newsreader, Outfit.
Process:
1. Write 3 words that describe the brand voice (e.g. warm, clinical, precise).
2. List the fonts you would normally reach for — reject them.
3. Find alternatives on Google Fonts, Pangram Pangram, or Future Fonts.
4. Pair a distinctive display/serif with a clean body sans.
Colour
Use OKLCH throughout, not hex or HSL. OKLCH is perceptually uniform — equal lightness steps look equal.
:root {
--ink: oklch(17.5% 0.008 52); /* near-black, warm tinted */
--muted: oklch(47% 0.013 57); /* secondary text */
--cream: oklch(95% 0.019 82); /* warm background */
--green: oklch(33% 0.065 196); /* brand accent example */
}
Tint all neutrals toward the brand hue at low chroma. Pure black (#000) and pure white (#fff) should not appear.
Banned CSS Patterns
These patterns mark a page as AI-generated and must never appear:
border-left: Xpx solid [colour]on cards, alerts, or list items — any width greater than 1pxbackground-clip: textwith a gradient (gradient text fill)- Glassmorphism used decoratively everywhere (blur + glow borders on every card)
- Identical card grids (same icon + heading + text repeated 3-6 times)
Spacing
Use a 4pt spacing scale with semantic tokens:
--sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
--sp-5: 20px; --sp-6: 24px; --sp-8: 32px; --sp-12: 48px;
--sp-16: 64px; --sp-24: 96px;
Vary spacing for hierarchy. Do not apply the same padding to every section.
10. Post-Launch Edit Ownership
Before choosing the hosting setup, answer: who needs to make copy or image changes after launch, and how often?
This question drives the hosting and CMS decision more than anything else.
| Who edits | How often | Right setup |
|---|---|---|
| John via Claude Code | Occasionally, on request | Static HTML on Cloudflare Pages or client domain. Redeploy with one command. No CMS needed. |
| VA (Camille) for copy changes | Regularly, without involving John | WordPress + ACF. VA edits text fields in WP admin. Design stays locked. |
| VA (Camille) for layout/section changes | Regularly | GHL native builder. VA stays in her trained environment. Accept design constraints. |
| Client (Kelsey/Tracey) self-service | Occasionally | WordPress + Elementor or Framer. Accept some design compromise for the independence. |
| Nobody — campaign page frozen after launch | Never | Static HTML anywhere. No CMS overhead needed. |
The Bottleneck Problem
Custom HTML pages built with Claude Code are fast to update (describe the change, Claude edits, redeploy in 60 seconds) but only if John is the person making the change. If Camille is supposed to handle landing page copy updates and she does not have Claude Code access, John becomes the bottleneck for every copy edit.
Rule: if the plan is for Camille to own copy updates on a page, do not build it in plain HTML. Use WordPress + ACF or GHL native so she can edit without code.
Rule: if the plan is for John to own the page with Claude Code, static HTML is fine and is actually faster than any CMS for iterating.
When Pitching The Custom Build To A Client
Be upfront about edit access before they commit. State clearly:
- The page looks better and loads faster than a GHL builder page.
- Copy or photo changes go through you (John), not self-service.
- Turnaround for a text change is a few minutes.
- If they want self-edit access, the option is WordPress + Elementor or ACF, with some trade-off on design quality.
Do not let a client assume they are getting a GHL-style drag-and-drop editor and then discover they cannot log in and change a headline.
11. File Organisation
Single Source Of Truth Rule
One file per project. Do not maintain two copies of the same page in different folders.
Correct location: client or prospect folder.
Clients/Prospects/[ClientName]/[project-folder]/index.html
Clients/Prospects/[ClientName]/[project-folder]/assets/
Do not duplicate into tools/ or .tmp/ for production files. Temporary previews in .tmp/ are disposable and should never become the source of truth.
If two copies exist, reconcile immediately: pick one, delete the other, update the client file and session log.
12. Demo-First Sales Pattern (Website Rebuilds)
For prospects who need to see before they commit:
- Build a premium one-page demo using Claude Code or Codex.
- Deploy to Cloudflare Pages for a shareable preview link.
- Send the link via WhatsApp with a short message: what you built, what can be changed, optional mention of ads if relevant.
- Wait for the prospect's reaction before scoping further.
- Once they respond positively, send pricing.
- Close on setup fee + monthly retainer.
- After agreement, rebuild properly with real assets and correct brand copy.
Do not send pricing before sending the demo. The demo anchors the value before the number lands.
The Cloudflare preview is a sales tool, not the final deliverable. The final build goes on the client's domain.
13. SEO Preservation (Website Rebuilds)
Before rebuilding any site that has existing indexed pages:
- Audit existing URLs — list every published page and its Rank Math score if available.
- Identify which pages Google has indexed — check Google Search Console if accessible, or run
site:domain.com. - Keep or redirect every indexed URL. Do not delete a page that Google has already indexed without a 301 redirect to an equivalent page.
- Preserve the homepage keyword target — if the current homepage ranks for a core term, the new homepage must target the same term.
- Rebuild treatment pages as SEO pages with: H1 containing the keyword, FAQ schema, local intent modifiers, internal links, and accurate alt text.
- Do not rely on Rank Math scores as proof of rankings. They are a checklist indicator, not a search position guarantee.
Recommended hybrid structure:
Homepage → conversion-optimised, clean CTA, premium design
Treatment pages → SEO-optimised, long-form, FAQ schema, keyword-rich
14. UK Aesthetics Compliance Rules
All copy on aesthetics clinic pages must follow these rules before going live.
Wording
| Avoid | Use instead |
|---|---|
| Botox | Anti-wrinkle treatment, botulinum toxin treatment |
| Filler (as a casual shorthand) | Dermal filler, lip filler |
| "Guaranteed results" | "Expected outcomes", "results vary by individual" |
| "Permanent" | "Long-lasting", "results that build over time" |
| "Safe" (as a blanket claim) | "Clinician-led", "clinically appropriate", "suitable for..." |
| "No risk" | "Minimal downtime", "non-surgical" |
Before/After Photos
- Add a disclaimer near any results imagery: "Results vary. Individual outcomes depend on the treatment area, skin type, and course followed."
- Do not make before/after the primary hook. Use them as secondary proof, not the headline claim.
Regulated Treatments
- Botulinum toxin (anti-wrinkle) can only be prescribed by a qualified prescriber in the UK.
- Do not imply that a practitioner administers prescription-only medicines without confirming their prescribing status.
- Do not use CQC-regulated language loosely (e.g. "medical clinic", "clinical", "doctor-led") unless the practitioner holds the relevant credentials.
Pricing
- Showing price ranges is allowed and recommended for transparency.
- Do not use "from £X" if the lowest price is not genuinely available.
- Course pricing should be presented as a total investment, not disguised as a per-session number only.
15. Asset Management
Priority order for imagery
- Real clinic photos — reception, treatment room, device, practitioner.
- Real before/after results (with consent and disclaimer).
- Brand-aligned stock — only if nothing real is available and the stock image is not recognisably generic.
Requesting assets from the client
Send this request early, ideally before starting the build:
To get the page looking its best, I need:
- 2-3 photos of the clinic interior or reception
- 1-2 photos of the treatment device or setup
- A practitioner photo if they are happy to be featured
- Any before/after results with patient consent
- Logo in SVG or high-res PNG if available
While waiting for real assets
Use placeholder structure images from the assets folder if they exist, or a neutral dark/cream colour block as a background. Never use obviously generic stock (white-coat models, staged smiling patients, stock devices).
Mark placeholder images with an HTML comment so they are easy to find and replace:
<!-- TODO: Replace with real Exion device photo once received from client -->
<img src="assets/placeholder-device.jpg" alt="Treatment device at [Clinic Name]">
Image format and compression
- Use WebP where possible for production (smaller file size, supported by all modern browsers).
- JPEG is acceptable for photos. PNG only for logos or images requiring transparency.
- Compress all images before uploading. Target: under 200KB per image for hero/above-fold, under 100KB for below-fold.
- Use
loading="lazy"on all below-fold images. - Use
fetchpriority="high"on the above-fold hero image.
Quick macOS compression with sips (no extra tools needed):
# Resize to max 900px wide (maintains aspect ratio, overwrites in place)
sips -Z 900 assets/kelsey-headshot.jpg
# Batch compress all JPEGs in assets folder
for f in assets/*.jpg; do sips -Z 900 "$f"; done
For the Nurse Kelsey v2 build, compressing a 4MB headshot to 900px reduced it to 113KB with no visible quality loss at display size. Always compress before deploying. A 4MB hero image is a hard fail on mobile QS.
16. Final Rule
Build for the patient/customer first, then wire the backend.
The page should never expose the machinery behind the campaign. GHL, tracking, qualification logic, and manual sync are backend decisions. The visitor should only experience:
This is relevant to me.
This clinic feels trustworthy.
I understand what happens next.
I know whether this is likely within my budget.
I can request the right consultation without confusion.
17. Case Studies
Dr Andrew Winter Aesthetics — Full site from scratch (May 2026)
site-build-from-scratch-dr-winter-case-study.md
19-page static HTML site built from zero in a single session: homepage, practitioner page, treatments hub, 2 treatment/location pages, 3 concern pages, 2 location pages, booking page, blog hub, and 3 blog articles — all with JSON-LD schema, canonical tags, and Cloudflare-ready headers. Documents the full build process, CSS component library, 8 bugs with root causes and fixes, Pexels image strategy, and a reusable checklist for future clinic site builds.
Activation Prompt
You are in Clinic SEO mode. This lane covers SEO delivery for aesthetics/dental clinic clients. Read lane-clinics.md in full before touching any client site. Priority order: GBP optimisation first, then treatment pages (1,500+ words, 10 sections), then concern pages, then blog clusters. Google treats aesthetics as YMYL — E-E-A-T, practitioner credentials, and real patient signals matter heavily. Never clone location pages. Every location page must have unique local content.
Lane: Client SEO Service Delivery
Lane: Aesthetics and dental clinic clients
Domains: Client-owned (Wix, WordPress/SiteGround, Cloudflare Pages)
Audience: Clinic patients searching locally on Google
Owner: Camille executes, John signs off on strategy and keyword choices
Priority: High — billable service, requested by Ayadi and Nova unprompted
Active clients: Ayadi (WordPress + Yoast), Nova Beauty (Wix)
Back to: MASTER.md
Aurea Growth — AI-Powered SEO Guide for Aesthetics Clinics
Scope: Practical, low-overhead SEO playbook for UK aesthetics/dental clinics.
Who executes: John (strategy + Claude Code) or Camille (content implementation).
Leverage: Claude Code and Codex handle the heavy lifting — writing, schema, GBP copy, keyword clustering. You implement.
0. Platform Snapshot (What Each Site Already Has)
From Wappalyzer audit (May 2026):
| Nova Beauty (Wix) | Ayadi (WordPress) | |
|---|---|---|
| Platform | Wix | WordPress + Elementor |
| SEO Plugin | None detected | Yoast SEO ✓ |
| Analytics | Facebook Pixel only | Site Kit (GA + Search Console) ✓ |
| CDN | Google Cloud CDN | SiteGround CDN |
| Schema | Wix auto (partial) | Yoast auto (full) |
| Hosting | Wix managed | SiteGround |
| Tech SEO readiness | Moderate | Strong |
What this means:
- Ayadi has a stronger baseline. Yoast + Site Kit = ready to optimize immediately.
- Nova has no Google Analytics. First action: connect GA4 + Search Console via Wix dashboard.
- Both sites are missing treatment-specific pages. That is the #1 gap for both.
1. Priority Stack — What To Do First
Do not try to do everything at once. This order matters.
Month 1 — Foundation (no content yet, just setup)
| Priority | Action | Who | Time |
|---|---|---|---|
| 1 | Connect Google Analytics 4 to Nova Beauty (Wix) | John | 20 min |
| 2 | Connect Google Search Console to Nova Beauty (Wix) | John | 10 min |
| 3 | Claim and fully optimize Google Business Profile for both clinics | John / Camille | 1.5 hrs each |
| 4 | Audit and fix NAP consistency (name, address, phone) across all directories | Camille | 2 hrs |
| 5 | Set up automated review request flow (GHL post-visit SMS → Google review link) | John | 1 hr |
| 6 | Build keyword list for each clinic using Claude Code + SEMrush/free tools | John | 1 hr |
Month 2 — Content Build
| Priority | Action | Who | Time |
|---|---|---|---|
| 7 | Create 8-12 treatment pages per clinic (Claude Code generates, Camille implements) | Both | 2-3 hrs/clinic |
| 8 | Add JSON-LD schema markup to every treatment page (Claude Code generates, paste in) | Camille | 30 min total |
| 9 | Optimize all meta titles and descriptions (Claude Code generates batch) | Camille | 1 hr |
| 10 | Write and implement GBP service descriptions for every treatment | Camille | 1 hr |
Month 3 — GEO + Growth
| Priority | Action | Who | Time |
|---|---|---|---|
| 11 | Restructure existing content for GEO (AI search) using Claude Code reformat prompt | Camille | 2 hrs |
| 12 | Publish 2-4 blog posts targeting informational keywords (how much does X cost, etc.) | Camille | 2 hrs |
| 13 | Submit site to relevant directories (Doctify, Fresha, Treatwell profile if kept, Phorest) | Camille | 1 hr |
| 14 | First review audit — are reviews coming in? Adjust automation if not | John | 30 min |
2. Google Business Profile — Full Optimization
This is free, high-leverage, and takes one afternoon. Do this before anything else.
Step-by-step setup
- Go to google.com/business and sign in with the clinic's Google account
- Claim the profile if not yet claimed
- Fill in every field. Do not leave anything blank.
Exact fields to complete
Business name: Exactly as it appears on signage — no keyword stuffing.
Primary category:
- Aesthetics clinic: "Medical Spa" or "Skin Care Clinic"
- Dental + aesthetics (Nova): "Dental Clinic" as primary, add "Medical Spa" as secondary
Secondary categories: Add all that apply:
- Laser Hair Removal Service
- Skin Care Clinic
- Medical Spa
- Beauty Salon (only if applicable)
Business description (250-300 words):
Use Claude Code to generate this (see prompt in Section 5). Key rules:
- Paragraph 1: Who you are, what you specialise in, why patients trust you (credentials, years of experience)
- Paragraph 2: Key treatments, differentiators (prescriber-led, non-invasive, medically supervised)
- Include location (East Finchley, North London) naturally — not forced
- Do NOT mention prices or offers here
Services tab: Add every treatment individually.
For each service include:
- Name of treatment
- Description (50-80 words, written by Claude — see prompt in Section 5)
- Price range or "Contact for pricing"
Photos: Minimum 20 photos.
- Clinic exterior (from street)
- Reception and waiting area
- Treatment rooms
- Before/after results (with patient consent)
- Team photos (practitioners with credentials visible)
- Equipment photos (device brand logos are trust signals)
- At least 1 new photo per month going forward
Hours: Exact, including special holiday hours. Keep these updated.
Q&A section: Pre-populate this yourself. Ask the 5 most common questions patients have and answer them. Claude Code can draft these (see prompt in Section 5).
3. Technical SEO — Platform-Specific Setup
3a. Wix (Nova Beauty)
Wix is not the ideal SEO platform but it is workable for a single-location clinic. Follow these steps.
Step 1: Connect Analytics (Critical — do this first)
- Wix dashboard → Marketing & SEO → Marketing Integrations
- Connect Google Analytics 4 (enter GA4 Measurement ID)
- Connect Google Search Console: Settings → Domains & Emails → Add Google Search Console
Step 2: Set up Wix SEO Basics
- Go to: Marketing & SEO → SEO → SEO Setup Checklist
- Complete every item in the checklist (takes 30 min)
- Enable the XML sitemap (it auto-generates — just make sure it's on)
- Set your primary domain (with or without www — pick one, stick to it)
Step 3: URL structure
- Keep URLs short and keyword-focused
- Format: /treatments/botox-north-london or /botox-north-london
- Avoid: /page-12345 or /copy-of-treatments
- In Wix: Edit page → Settings → SEO → Page URL
Step 4: Meta tags on every page
For each treatment page, fill in:
- SEO Title: [Treatment] in [Location] | [Clinic Name] (max 60 characters)
- Meta Description: 150-160 characters — state the treatment, location, and one differentiator
Use Claude Code to generate these in bulk (see Section 5).
Step 5: Add JSON-LD schema
Wix supports custom JSON-LD. For each treatment page:
- Edit page → Settings → Advanced → Additional meta tags
- Paste in the schema code generated by Claude (see Section 5)
Step 6: Image optimization
- Before uploading any image to Wix, rename the file descriptively
- Bad: IMG_3845.jpg
- Good: botox-north-london-nova-beauty.jpg
- After upload, add alt text to every image via the Wix image editor
- Use Claude to generate alt text in bulk from a list of image names
Key Wix SEO limitations to know:
- You cannot install SEO plugins like Yoast — all optimization is manual
- Wix's built-in performance is slower than WordPress on complex pages (acceptable for a clinic)
- URL customization is limited but sufficient for this use case
- Structured data is manual JSON-LD paste — Claude generates it for you
3b. WordPress + Yoast (Ayadi)
Ayadi already has the best possible setup. Yoast is installed, Site Kit is connected. Optimize the configuration.
Step 1: Yoast configuration
- Go to: Yoast → General → Features
- Make sure all are ON: SEO analysis, Readability analysis, Schema, XML Sitemaps
Step 2: Set your site identity in Yoast
- Yoast → General → Site Representation
- Choose "Organisation" (not individual)
- Add clinic name, logo, business type ("MedicalBusiness")
Step 3: Schema type for pages
- For treatment pages: Yoast → Schema → Page type = "Web Page", Article type = "None"
- Schema for services is added via custom JSON-LD (Claude generates it — see Section 5)
Step 4: Yoast for every treatment page
In the Yoast panel at the bottom of each page editor:
- Focus keyword: [treatment] [location] (e.g. "HIFU East Finchley")
- SEO title: [Treatment] in [Location] | Ayadi Beauty
- Meta description: 150-160 characters
- The Yoast traffic light will tell Camille if the page passes — aim for green on both SEO and Readability
Step 5: Internal linking
- Every treatment page links to at least 2 related treatment pages
- Every treatment page links to the contact/booking page
- The homepage links to all main treatment category pages
Step 6: Cornerstone content
In Yoast, mark your most important pages as "Cornerstone Content" — these get prioritised in Yoast's internal link suggestions.
Cornerstone pages: Botox, Fillers, HIFU, Laser Hair Removal, whatever the top 3 treatments by revenue are.
4. Treatment Page Structure — The Core SEO Asset
Every treatment needs its own dedicated page. This is the single highest-impact SEO action.
How many pages to build
Nova Beauty targets:
- Anti-wrinkle (Botox) — North London
- Dermal Fillers — North London
- HIFU — East Finchley
- Profhilo / Polynucleotides — North London
- Laser / Photofractional — East Finchley
- Dental Implants — East Finchley
- Invisalign — North London
- IV NAD+ Therapy — London (broader — less local competition)
- Exosome Therapy — London
- Microneedling — North London
That is 10 pages. Build all 10 before anything else.
Ayadi targets:
- EMSculpt Neo / BTL Exion — North London
- Geneo X Facial — East Finchley
- Body Contouring — North London
- Laser Hair Removal — East Finchley / North London
- Clinical Massage — East Finchley
- Facials — East Finchley
That is 6-8 pages. Each one targets a different keyword combination.
Exact page template
Use this structure for every treatment page. Claude Code generates the content — Camille pastes it in.
URL: /treatments/[treatment-name]-[location]
Example: /treatments/hifu-east-finchley
H1: [Treatment] in [Location] | [Clinic Name]
Example: HIFU Treatment in East Finchley | Nova Beauty Clinic
Opening paragraph (60-80 words):
State what the treatment is, who it is for, what results patients can expect,
and how long results last. Include the target keyword in the first sentence.
H2: What is [Treatment]?
Plain-language explanation. No medical jargon without explanation.
3-4 short paragraphs or a bullet list.
H2: How [Treatment] Works
Step-by-step process: before, during, and after.
Keep it factual and reassuring.
H2: Key Benefits
Bullet list of 5-8 patient-outcome benefits.
Focus on: results, downtime, how it compares to alternatives.
Example: "No surgery, no downtime — results in one session"
H2: Ideal Candidate
Who is a good fit for this treatment.
Who to consult on first (skin type, contraindications — brief and reassuring, not frightening).
H2: Results & Timeline
When they see initial results.
When results peak.
How long results last.
What affects longevity.
H2: Before & After
[Image gallery placeholder or actual images with alt text]
H2: Frequently Asked Questions
Minimum 6 questions. Format as question/answer pairs.
Must include: How much does [treatment] cost? Does [treatment] hurt?
How long does [treatment] last? How many sessions do I need?
What should I do before/after? Is [treatment] safe?
H2: Book Your [Treatment] Consultation
Short closing paragraph (2-3 sentences).
One clear CTA: a button or embedded form linking to the booking system.
Include phone number and WhatsApp if applicable.
Local keyword targeting
Format: [Modifier] + [Treatment] + [Location]
Use these location modifiers for East Finchley clinics:
- East Finchley
- North London
- N2 (postcode — some patients search by postcode)
- Finchley (without "East")
- Highgate (5 min away — searches spill over)
- Muswell Hill (adjacent)
Do not try to rank for "Botox London" — too competitive. Start with East Finchley and North London.
5. Claude Code Workflow — Prompts and Processes
This section is the core of the AI leverage. John or Camille uses these prompts. Claude Code does the work.
How the 6 workflows fit together
There are 6 workflows. They are not all equal. Read this before diving in.
F is always first. Run it once per clinic at the start. It gives you the keyword list that drives everything else — which treatments to target, which location modifiers to use, which blog topics to write. Do not run A, B, C, D, or E before you have run F.
A and E are always paired. Every time you generate a treatment page with A, you immediately run E on the output. A writes the page. E restructures it for AI search. One does not get published without the other. Think of them as one step in two parts.
B, C, D are one-time batch runs per clinic. Once all treatment pages are written (after all your A+E runs), run B to generate all meta titles and descriptions in a single prompt. Run C to generate all schema markup in one go. Run D once for GBP content (business description, service descriptions, Q&A). These do not repeat unless the clinic adds new treatments.
Sequence per clinic:
Step 1 — Run F once → get keyword list
Step 2 — Run A+E per treatment → build all treatment pages
Step 3 — Run B once → all meta titles + descriptions
Step 4 — Run C once → all schema markup
Step 5 — Run D once → all GBP content
How many times to run each workflow for Nova and Ayadi:
| Workflow | Nova Beauty | Ayadi | Notes |
|---|---|---|---|
| F (keyword research) | 1x | 1x | Once per clinic at start |
| A+E (treatment pages) | 10x | 6-8x | Once per treatment, always paired |
| B (meta batch) | 1x | 1x | After all pages are written |
| C (schema batch) | 1x | 1x | After all pages are written |
| D (GBP content) | 1x | 1x | Once per clinic |
Total runs for both clinics combined: roughly 20-22 A+E pairs, 4 batch runs (B, C, D, F x2).
Who runs what:
- John runs F (keyword research requires judgment on which keywords to include)
- John or Camille runs A+E (mechanical once you have the keyword list)
- Camille runs B, C, D (batch prompts, pure execution)
- Camille implements everything into Wix (Nova) or WordPress (Ayadi)
Workflow A — Generate a treatment page
You are a medical aesthetics SEO copywriter for a UK clinic.
Write a complete, SEO-optimised treatment page for the following:
- Treatment: [INSERT TREATMENT NAME]
- Clinic: [INSERT CLINIC NAME]
- Location: [INSERT AREA, e.g. East Finchley, North London]
- Primary keyword: [e.g. "HIFU East Finchley"]
- Secondary keywords to include naturally: [e.g. "HIFU North London, face lifting East Finchley, non-surgical facelift N2"]
- Clinic differentiators: [e.g. "medically supervised, 25 years experience, Obagi-certified"]
- Target word count: 900-1,100 words
Page structure required:
H1 → Opening paragraph → H2: What is it → H2: How it works → H2: Benefits (bullet list) → H2: Ideal candidate → H2: Results & timeline → H2: FAQs (6 questions minimum) → H2: Book a consultation
Tone: Authoritative and warm. Clinical but not cold. No jargon without explanation. Short paragraphs (2-3 sentences max). Definitive statements, not vague claims.
Do NOT include: Prices (unless instructed), competitor names, unsubstantiated superlatives ("best in London").
Output the full page content ready to paste into [Wix/WordPress].
Workflow B — Generate meta titles and descriptions in batch
Write SEO meta titles and meta descriptions for the following treatment pages at [CLINIC NAME] in [LOCATION].
Rules:
- Title: max 60 characters, format = [Treatment] in [Location] | [Clinic Name]
- Description: 145-155 characters, include treatment + location + one differentiator + implicit CTA
- No clickbait, no ALL CAPS, no em dashes
Pages:
1. Botox / Anti-wrinkle injections
2. Dermal fillers
3. HIFU face lifting
4. Profhilo
5. Microneedling
[Continue for all pages]
Output as a table: | Page | Title | Description |
Workflow C — Generate JSON-LD schema for a treatment page
Generate valid JSON-LD structured data markup for the following:
Page type: Service page for a UK medical aesthetics clinic
Clinic name: [CLINIC NAME]
Clinic address: [FULL ADDRESS WITH POSTCODE]
Clinic phone: [PHONE]
Clinic website: [URL]
Treatment: [TREATMENT NAME]
Treatment description: [1-2 sentences]
Price range: [e.g. "£180–£400" or omit if not sharing prices]
Provider type: MedicalBusiness
Include: LocalBusiness + MedicalBusiness schema, Service schema for the treatment, AggregateRating if provided.
Output: Production-ready JSON-LD code block only. No explanation.
Paste the output into:
- Wix: Edit page → Settings → Advanced → Additional meta tags
- WordPress: Use a plugin like "Schema Pro" or paste in the page's Custom HTML block
Workflow D — Generate GBP content
Business description:
Write a Google Business Profile description for [CLINIC NAME], a [type of clinic, e.g. "doctor-led medical aesthetics clinic"] in [LOCATION].
Details:
- Key treatments: [list top 5]
- Credentials: [e.g. "prescriber-led, CQC registered, 25 years experience"]
- Differentiators: [e.g. "no Groupon deals, no discounts, outcome-focused"]
- Target patient: [e.g. "discerning patients in N2 and surrounding areas"]
Rules:
- 200-300 words
- Include location (area name and postcode) naturally
- Do not mention prices
- Do not use em dashes
- No generic phrases like "state of the art" or "cutting edge"
- End with a soft CTA: "Book a consultation" or "Get in touch"
Service descriptions (GBP):
Write Google Business Profile service descriptions for the following treatments at [CLINIC NAME]:
[List of 8-10 treatments]
Rules per description:
- 60-80 words each
- What the treatment does + who it is for + one key benefit
- Include location if it fits naturally
- No prices
- No em dashes
Output as a list: Service name → Description
GBP Q&A pre-population:
Write 8 Google Business Profile Q&A entries for [CLINIC NAME], an aesthetics clinic in [LOCATION].
Questions should cover:
- Opening hours and booking process
- Whether the clinic accepts walk-ins
- What to expect at a first consultation
- Whether treatments are medically supervised
- How to find the clinic (parking, public transport)
- Whether they cater to nervous or first-time patients
- What makes them different from beauty salons
- Cancellation policy
Output format: Q: [question] A: [answer, 40-60 words]
Workflow E — GEO restructure (AI search optimization)
Once a treatment page is drafted, run this to optimize it for ChatGPT, Perplexity, and Google AI Overviews:
Rewrite the following treatment page content to be optimized for AI search engines (ChatGPT, Perplexity, Google AI Overviews).
Rules for AI-search optimization:
- Maximum 3 sentences per paragraph
- Lead every section with the direct answer first
- Convert any long paragraphs into bullet lists where possible
- Add specific numbers and timelines (e.g. "results appear within 3-7 days" not "results appear quickly")
- Replace vague claims with definitive statements
- Add a short "Quick Summary" section at the top (4-6 bullet points: what it is, who it is for, how long results last, downtime, price range if available)
Do not change the page structure or headings. Only restructure the prose within each section.
[PASTE TREATMENT PAGE CONTENT HERE]
Workflow F — Keyword research with Claude
I am doing local SEO for [CLINIC NAME], a [type of clinic] in [SPECIFIC AREA, e.g. East Finchley, North London, N2].
Generate a keyword list targeting local patients. Focus on:
1. Treatment-specific keywords with location modifier (e.g. "botox East Finchley")
2. Intent-based keywords (patients ready to book, not just browsing)
3. Question-based keywords for blog content (e.g. "how much does HIFU cost in London")
4. Adjacent keywords that capture patients earlier in the decision process
For each keyword, estimate:
- Search intent (commercial, informational, navigational)
- Approximate competition level (low/medium/high based on your knowledge)
- Which page on the site should target this keyword
Treatments to target: [list all clinic treatments]
Avoid: Brand keywords for other clinics, keywords targeting practitioners (not patients), national keywords too broad to compete on.
Output as a table: Keyword | Intent | Competition | Target Page
6. Review Automation — The Off-Page SEO Lever
Reviews are the fastest local SEO signal after treatment pages. Every new Google review improves local pack ranking.
Setup (GHL-based, already in John's stack)
- Create a GHL workflow: trigger = appointment completed (status change in GHL or Vagaro webhook)
- Wait: 60-90 minutes after appointment end time
- Send SMS: "Hi [name], thank you for visiting us today. If you have a moment, we'd love to hear how it went: [Google review link]"
- If no response after 48 hours: send one follow-up email with the same link
- Cap at 2 touchpoints — no more
Google review link format:
https://search.google.com/local/writereview?placeid=[PLACE_ID]
Get the Place ID from Google Business Profile → Manage profile → Get more reviews → Copy link
Review velocity targets
Both Nova and Ayadi have very few reviews relative to their quality. Targets:
- Month 1-3: 1 new review per week minimum
- Month 4+: 2 per week as patient volume grows
At 2 reviews/week, you reach 50 reviews in ~6 months. That alone moves a clinic from invisible to visible in local pack results for most treatment keywords in East Finchley.
What to do with reviews for SEO
- Respond to every review within 48 hours. Include the treatment name and location naturally.
Example: "Thank you so much for sharing your experience with our HIFU treatment in East Finchley..."
This is free keyword placement in a Google-indexed response. - Flag and report any fake negative reviews promptly.
7. GEO — Optimising for AI Search (ChatGPT, Perplexity, Google AI Overviews)
AI-referred web traffic grew 527% year-over-year in early 2025. By the time your clients rank on traditional search, GEO is already the next frontier. Build it in from the start.
See MASTER.md for the universal GEO rules and restructure prompt.
GEO content to create separately (beyond treatment pages)
FAQ pages: A dedicated FAQ page per treatment is high-value for AI citation. Patients often ask AI tools questions like "how many sessions of laser hair removal do I need in the UK?" A well-structured FAQ page has a high chance of being cited.
Comparison content: "HIFU vs. surgical facelift: key differences" — AI models love comparison content. One blog post per competitive comparison, written using the GEO restructure prompt.
Local authority content: "What to look for in an aesthetics clinic in North London" — written from the clinic's perspective. This positions the clinic as the authoritative voice and increases citation probability for local queries.
8. Blog Strategy — Only What You Can Sustain
Do not publish 100 blog posts. Publish 6-10 high-quality, GEO-optimized posts and keep them updated.
Blog topics to prioritise (informational + high local intent)
Cost/pricing posts (high conversion intent):
- "How much does Botox cost in North London in 2026?"
- "HIFU price guide: what to expect in a London clinic"
- "Dental implants vs veneers: cost comparison in East Finchley"
Process/expectation posts (pre-decision research):
- "What to expect at your first Botox consultation in the UK"
- "How many sessions of laser hair removal do you need?"
- "What is the recovery like after HIFU?"
Adjacent content (top of funnel):
- "Signs you might benefit from Profhilo (and who it is not right for)"
- "HIFU vs. thread lifts: which is better for skin laxity?"
Blog cadence
- 1-2 posts per month is sufficient for a local clinic
- Prioritise updating existing posts over creating new ones after 6 months
- Always check: does this post target a keyword with real local search volume before writing it?
9. Directory & Citation Building
NAP consistency (Name, Address, Phone) across the web is a local ranking factor. Camille can do this in 2-3 hours once, then it only needs checking quarterly.
Directory list for UK aesthetics clinics
High priority (submit first):
- Google Business Profile (already covered)
- Bing Places for Business (free, often forgotten)
- Doctify (UK healthcare review platform — important for medical credibility)
- Fresha (if the clinic uses or plans to use it for booking)
- Treatwell (even if moving away from it as a booking channel, the listing still drives discovery)
- Yell.com
- Thomson Local
- Trustpilot
Secondary priority:
- Facebook Business Page (check address is correct)
- Instagram Business profile (check phone/website)
- Whatclinic.com
- Booksy (if relevant to treatment mix)
NAP format to use consistently everywhere:
Nova Beauty Clinic
260 East End Road
East Finchley
London
N2 8AU
020 5925 1232
Any variation in capitalisation, comma placement, or abbreviation counts as an inconsistency. Pick one format and replicate it exactly.
10. Ongoing Cadence — What To Do Each Week/Month
Weekly (Camille, 30-45 min)
- Check if any new Google reviews came in — respond to all within 48 hours
- Check GBP for new Q&A submissions from patients — answer any within 24 hours
- Flag any technical errors in Search Console (Ayadi) or Wix SEO dashboard (Nova)
Monthly (John or Camille, 1-2 hrs)
- Review Search Console data: which queries are generating impressions? Which pages are ranking but not getting clicks?
- Publish or update 1-2 blog posts
- Add 5-10 new photos to each clinic's GBP
- Check review count and velocity — is the automation working?
Quarterly (John, 1 hr)
- Full keyword position check: are the treatment pages moving up in rankings?
- Review NAP consistency across directories — anything changed?
- Update any treatment pages with new clinical information or updated pricing notes
- Update "2026" references in content to stay current
11. What Not To Do
Do not keyword stuff. Writing "botox east finchley botox north london botox n2" in a paragraph kills the page.
Do not create thin location pages. For a single-location clinic, creating 40 near-identical pages triggers a duplicate content penalty. Build 10 high-quality unique pages.
Do not ignore page speed. Compress every image before uploading. Use TinyPNG or Squoosh.
Do not build backlinks through link farms. Only pursue: Doctify, local press mentions, genuine patient review platforms.
Do not use AI-generated content without review. Claude Code generates the draft. A human reviews for accuracy before publishing.
12. Measuring Success
After 60-90 days, check these metrics:
| Metric | Tool | What to look for |
|---|---|---|
| Organic impressions | Google Search Console | Increasing month-over-month |
| Treatment page clicks | Google Search Console | Treatment pages appearing with clicks |
| GBP calls and directions | Google Business Profile Insights | Increasing post-optimisation |
| Google review count | GBP | Adding 1+ per week |
| Local pack appearance | Manual search (incognito, location set to East Finchley) | Do you appear in the 3-pack for any treatment? |
| Organic sessions | GA4 | Month-over-month growth |
Do not obsess over keyword position before 90 days.
Appendix: Quick Reference — Claude Code Prompts at a Glance
Execution order (always follow this sequence)
1. F — Keyword research → run once per clinic, before anything else
2. A — Treatment page → run once per treatment (10x Nova, 6-8x Ayadi)
3. E — GEO restructure → run immediately after every A, never skip
4. B — Meta titles + descs → run once after all A+E pages are done
5. C — Schema markup → run once after all A+E pages are done
6. D — GBP content → run once per clinic (3 sub-prompts: description, services, Q&A)
Who does what
| Task | John | Camille |
|---|---|---|
| Run F (keyword judgment) | Yes | No |
| Run A+E (content generation) | Either | Either |
| Run B, C, D (batch outputs) | Either | Yes |
| Implement into Wix (Nova) | No | Yes |
| Implement into WordPress (Ayadi) | No | Yes |
| Connect GA4 + Search Console (Nova) | Yes | No |
| Set up GHL review automation | Yes | No |
| Optimise GBP (upload photos, fill fields) | Either | Yes |
13. 2026 Site Architecture for Serious Clinics
Added 2026-05-15. Source: synthesis of current aesthetics SEO data — CosmediCheck, Boutique SEO, Clinic Grower, YEAH! Local, Local SEO Services UK.
Google treats aesthetics as YMYL (Your Money or Your Life) healthcare content. Trust, local authority, practitioner credibility, and real patient signals carry heavy weight in the ranking algorithm. The clinics winning local search are not the best marketers — they are the ones with the strongest combination of structural and entity signals.
The 4-Level Architecture
The correct structure for a serious multi-treatment aesthetics clinic:
/ — Homepage (brand + authority hub)
/treatments/ — Treatment hub (navigation + internal link distribution)
/treatments/botox/ — Core treatment page (1,500-3,000 words, money page)
/treatments/lip-fillers/ — Core treatment page
/concerns/tired-eyes/ — Concern page (problem-first SEO)
/concerns/jowls/ — Concern page
/locations/london/ — Real location page (not cloned treatment pages)
/locations/chiswick/ — Real location page
/blog/profhilo-vs-pn/ — Blog cluster (supporting topical authority)
/practitioners/dr-x/ — Practitioner entity page
This is NOT: /botox-london/, /botox-chelsea/, /botox-fulham/ with 95% identical content. That pattern gets algorithmically suppressed as doorway spam.
What a 2026 Treatment Page Looks Like
Minimum 1,500 words. 3,000+ for competitive treatments like Botox, fillers, Profhilo. Sections:
- Hero — clear H1, subhead, CTA, real clinic image, trust badges, review snippet, practitioner name
- Immediate trust block — GMC/NMC number, years experience, clinic awards, press, real practitioner photo
- "What is [Treatment]?" — mechanism, science, category, who it helps, alternatives. Captures informational and AI search.
- Candidate section — "Who is this best for?" Captures symptom/concern/long-tail intent (tired eyes, crepey skin, skin laxity after weight loss)
- Treatment areas — under-eyes, neck, hands, face, décolleté. Each adds semantic relevance.
- Process — consultation, preparation, injection process, downtime, recovery, aftercare
- Results timeline — when results appear, how many sessions, longevity, maintenance. Reduces pogo-sticking.
- Real FAQs — pulled from People Also Ask, GBP Q&A, Reddit, consultation objections. FAQ schema is non-negotiable.
- Before & After — optimise alt text, filenames, captions, practitioner attribution. Example filename:
before-after-polynucleotides-under-eyes-london.jpg - Internal links — every treatment page links to related treatments, concern pages, practitioner page, location pages, relevant blog posts
Concern Pages — Underused Ranking Gold
Problem-first SEO captures patients before they know which treatment they want. Build these:
/concerns/tired-eyes/— links to: polynucleotides, tear trough filler, under-eye treatment blog/concerns/jowls/— links to: thread lifts, Morpheus8, skin tightening/concerns/acne-scars/— links to: microneedling, skin peels, collagen stimulation/concerns/skin-laxity/— links to: Profhilo, Morpheus8, collagen stimulation, blog
These pages rank well because patients search problems before treatments. They also build internal link authority back to core treatment pages.
What a GOOD Location Page Looks Like
Real clinic pages. Not cloned treatment pages with city names swapped.
Each location page must have:
- Real address, embedded map, parking, transport, nearby landmarks
- Clinic-specific photos (not stock photos used across all locations)
- Staff specific to that location
- Unique local content — talk about local clientele, common treatments, demographic patterns, clinic-specific expertise
- Local reviews and testimonials
- Embedded treatment modules: short summaries of treatments available at that location with links to the full treatment pages (not duplicating the full pages)
- "Patients travel from [nearby areas]" to expand local relevance
Example of real local content: "In Chiswick, many patients come to us for subtle regenerative treatments rather than volume-focused filler work." That is unique and useful. That is what Google rewards.
GBP — Still One of The Strongest Local Ranking Factors
Separate GBP per physical location. For each:
- Unique photos per clinic (not the same stock images)
- Treatment services configured properly in the Products/Services section
- Booking links connected
- Regular posts (minimum monthly)
- Practitioner photos and videos
- Q&A populated with clinic team answers
Review wording matters. Coach patients to mention treatment + location. Natural examples:
- "Best lip filler clinic in Chiswick"
- "Dr X explained polynucleotides clearly, really reassured me"
- "Profhilo in Acton — exactly what I was looking for"
Those review strings reinforce both entity relevance and local geographic signals simultaneously.
Schema Priority List
Most clinics implement less than half of this. Do all of it:
| Schema | Where | Priority |
|---|---|---|
MedicalBusiness or MedicalClinic |
Homepage, location pages | Critical |
Physician |
Homepage, practitioner page | Critical |
FAQPage |
Every treatment page, every blog post | High |
Article |
Every blog post | High |
BreadcrumbList |
All pages except homepage | High |
LocalBusiness |
Location pages | High |
Service |
Core treatment pages | Medium |
Review / AggregateRating |
Homepage, treatment pages | Medium — only if real reviews |
AI Search / GEO Considerations
AI systems (ChatGPT, Perplexity, Google AI Overviews) reward:
- Clean structure with clear headings
- Semantic clarity — what is it, who is it for, what does it cost, what is the downtime
- Expert attribution on every claim (practitioner name, credential)
- Concise, direct answers before expanded explanation
- FAQ formatting throughout
- Entity consistency — same practitioner name, GMC number, clinic name across all pages and external profiles
Pages should answer: what, who, cost, downtime, risks, alternatives, candidacy — directly, not buried in prose.
Internal Linking — The Most Underused Lever
Every treatment page should link out to:
- Related treatments (Profhilo → Polynucleotides)
- Concern pages (anti-wrinkle → concerns/tired-look)
- Practitioner page
- Location pages
- Relevant blog posts
This is one of the biggest ranking levers in healthcare SEO and almost every clinic fails at it completely.
What Wins Local Search — Summary
| Signal | Priority |
|---|---|
| GBP authority (completeness, photos, posts, reviews) | 1 |
| Review volume + review wording quality | 2 |
| Website speed (mobile) | 3 |
| Real, unique location pages | 4 |
| Deep treatment pages (1,500+ words, 10 sections) | 5 |
| Practitioner trust signals (GMC, photos, credentials) | 6 |
| Internal linking (treatment ↔ concern ↔ blog) | 7 |
| Topical authority blog clusters | 8 |
| Consistent local citations | 9 |
| Concern pages (problem-first SEO) | 10 |
Activation Prompt
You are in Aurea Brand SEO mode. This lane targets UK clinic owners searching for growth solutions. Read lane-aurea.md in full. Domain: insights.aureagrowth.co (Cloudflare Worker). Content angle: operator-level intelligence, not generic marketing advice. Camille publishes after John reviews. Run the GEO pass (Workflow E) on every draft before publishing.
Lane: Aurea Brand Content
Lane: Aurea Growth agency brand
Domain:insights.aureagrowth.co(Cloudflare Worker)
Audience: UK aesthetics and dental clinic owners
Owner: John (editorial), Camille (publishing execution)
Priority: High — pre-sells trust behind Mailman outreach
Back to: MASTER.md
Aurea Growth — Content Engine Master Guide
Strategy, system map, weekly workflow, brand rules, and troubleshooting in one place.
Related navigation:
- [[MASTER_GUIDE|Master guide]]
- [[CLAUDE|Agent rules]]
- [[docs/Aurea Growth V5|Aurea Growth product architecture]]
- [[research/content-insights-base|Content insights base]]
- [[aurea-growth-encyclopedia/wiki/index|Aurea Growth encyclopedia]]
- [[memory/project_content_doctrine|Aurea content doctrine]]
- [[workflows/SKILL_ROUTER|Skill router]]
1. The Strategic Logic
Aurea Growth sells a high-trust, high-ticket service to clinic owners. Content exists for one reason: to make every sales conversation easier to win.
SEO rules now in force
- Target commercial and transactional keywords only.
- Do not create separate pages for synonymous searches with the same buying intent.
- Reverse-engineer LLM citations before you outline. If ChatGPT, Gemini, or Perplexity cite listicles, pricing pages, or service pages, match that format exactly.
- Use competitor URLs as upgrade targets. The goal is not to be different. The goal is to be the clearest, most decision-useful version of the page already winning.
- Treat technical SEO as part of publishing, not a later clean-up step. PageSpeed, schema, sitemap, robots, and image compression are part of the workflow.
- Traffic is good when it is intention-led and routed into qualification. Traffic is bad when it is broad, unfiltered, and sent toward an open diary.
Content does three jobs:
- Pre-sells trust. A clinic owner who receives a Mailman letter and Googles you should land on 5–10 sharp articles that confirm you understand their world. By the time they get on a call, they don't need convincing — they've already read it.
- Builds inbound over time. Bottom-of-funnel SEO content ranks for the searches clinic owners are making when they are close to acting. Slow to kick in (2–4 months), but compounds permanently.
- Dual-audience leverage. Every piece serves two audiences simultaneously. Patients read it to understand their treatment. Clinic owners read it and realise this person understands their business. One post, two jobs.
Content is not the primary revenue channel right now. Mailman is. Content makes Mailman work better.
1.1 Skill Layer To Consult
Before writing new content, repurposing assets, or inventing ad copy frameworks from scratch, check the relevant skill-routing and context files first:
memory/MEMORY.md-> installed command-style marketing skills and when to use themworkflows/SKILL_ROUTER.md-> trigger -> skill -> context mappingmemory/project_content_doctrine.md-> non-negotiable Aurea content rulesdocs/aurea-copywriting-context.md-> Aurea-facing copy rulesdocs/aurea-ad-creative-context.md-> Meta / Google creative rules
Supporting command-style skill files live in:
- /Users/johntossou/.claude/commands/copywriting.md
- /Users/johntossou/.claude/commands/paid-ads.md
- /Users/johntossou/.claude/commands/ad-creative.md
These are useful for structure and variation frameworks.
They do not override Aurea doctrine.
2. System Map
research/
content-insights-base.md ← The brain. All market intelligence lives here.
aurea-content-engine/
scrapers/blog_writer.py ← The agent. Reads an outline, writes the post.
outputs/outlines/ ← The queue. One JSON file = one article.
outputs/voice_model.json ← Style reference (sentence length, tone, readability).
outputs/blog_posts/ ← Where finished articles land.
config.yaml ← Positioning, pillars, approved/forbidden phrases.
.env ← ANTHROPIC_API_KEY lives here.
The flow is linear:
Insight (Mailman / observation / market research)
↓
Write an outline (JSON in outputs/outlines/)
↓
Run the blog writer
↓
Article lands in outputs/blog_posts/
↓
Publish to Ghost → repurpose to IG / ad hooks / video
When choosing how to create or repurpose an asset:
- use project_content_doctrine.md for positioning and CTA rules
- use aurea-copywriting-context.md for Aurea-facing copy and operator voice
- use aurea-ad-creative-context.md when the output becomes an ad hook, creative brief, or paid asset
What's built
| Component | What it does | Location |
|---|---|---|
| Content insights base | Central knowledge store: patient psychology, clinic owner pain, real verbatim language, SEO keyword bank | research/content-insights-base.md |
| Article outline queue | JSON files defining each article's structure, editorial truths, and target keywords | aurea-content-engine/outputs/outlines/ |
| Blog writer | Python script: reads outline, calls Claude, outputs a full blog post | aurea-content-engine/scrapers/blog_writer.py |
| Branded HTML blog preview | Full Aurea-branded page preview (Canela font, brand colours, logo, sidebar TOC) | aurea-content-engine/outputs/blog_posts/preview_*.html |
| IG carousel generator | Outputs 6 branded HTML slides (1080x1080) from a blog post insight | aurea-content-engine/outputs/instagram/ |
| Brand config | Voice rules, forbidden phrases, forbidden punctuation, tone guidelines | aurea-content-engine/config.yaml |
Planned (not yet built)
| Component | What it does | Priority |
|---|---|---|
| Ghost blog | Hosted at insights.aureagrowth.co — where all articles publish |
Set up manually (15 min) |
| Playwright PNG export | Screenshots each IG carousel HTML slide to 1080x1080 PNG | Build next |
| Repurposing script | Takes a finished blog post and outputs IG copy, video script, and ad hooks in one run | Build next |
| Creatomate video render | REST API: sends slide content, receives rendered MP4 Reel | Evaluate (~$49/month) |
| Ghost API auto-post | Pushes finished blog post directly to Ghost via Content API | After Ghost is live |
| Buffer scheduling | Queues IG posts (PNGs) and video for timed publishing | After video pipeline is ready |
What's been ruled out
| Tool | Why |
|---|---|
| Canva API | Enterprise-only, requires ByteDance partnership approval |
| CapCut API | Same — enterprise/ByteDance only |
| Medium as main hub | Splits domain authority, wrong audience signal |
| LinkedIn (active channel) | Not a current priority |
| Twitter/X automation | Low ROI for clinic owner audience |
3. One-Time Setup
The engine is installed at aurea-content-engine/. Dependencies are in requirements.txt and were installed in the original build. The voice model (outputs/voice_model.json) is already extracted.
Only thing needed to run: an ANTHROPIC_API_KEY in a .env file inside the content engine directory.
cd "/Users/johntossou/Desktop/Aurea Growth/Claude Code Workflow/aurea-content-engine"
echo "ANTHROPIC_API_KEY=sk-ant-YOUR_KEY_HERE" > .env
Get the key from: console.anthropic.com → API Keys.
4. The Weekly Workflow
One cycle per week. ~90 minutes total.
Step 1 — Pick an insight
Every article starts with a real observation. Not a keyword. Not a topic. An observation about how clinics behave, how patients think, or what goes wrong between ad and booking.
Sources:
- A Mailman audit you just wrote
- A pattern that came up in a sales conversation
- A Reddit thread or market research finding in research/content-insights-base.md
- A client delivery note where something surprised you
The test: can you complete this sentence in one line?
"Clinics are losing money because __."
"Patients feel disappointed because __."
If yes, that's the article.
Then force the insight through this filter before you write anything:
- Is the keyword commercial or transactional?
- Is the search intent distinct from pages we already have?
- What content format do AI engines already cite for that prompt?
- Which competitor URL is currently closest to winning that intent?
Step 2 — Create an outline (JSON)
Create a new file in aurea-content-engine/outputs/outlines/. Name it sequentially: 08_your_topic_outline.json.
See brief-template.md for the full field specification.
Content pillars — assign one per article:
| Pillar | Audience | Lead with |
|---|---|---|
| The Economics | Clinic owner | Revenue leak, cost per slot, no-show rate |
| The Problem | Patient | The symptom — tired, hollow, overnight ageing |
| The Fear | Patient | Risk not yet voiced — pain, botched result, wasted money |
| The Expectation | Patient | What actually happens — timelines, post-treatment reality |
| The Standard | Both | What good looks like — clinical, conservative, evidence-led |
Structural rules:
- Every H2 should address one question a reader would actually have
- H3s go one level deeper — specific, not vague ("The economics of an empty slot vs a no-show" not "Examples")
- editorial_truth is the most important field. Without concrete claims, the output is generic filler
- intent_signature must be unique. If two keywords have the same signature, they belong on one page
- llm_citation_target should be chosen after checking real AI citations, not guessed in isolation
- CTA must always be low-pressure: "book a clinical assessment" or "map your booking flow in 10 minutes" — never "call us today"
Step 3 — Run the blog writer
cd "/Users/johntossou/Desktop/Aurea Growth/Claude Code Workflow/aurea-content-engine"
Generate one specific article:
python3 -c "
from scrapers.blog_writer import BlogWriter
writer = BlogWriter()
writer.load_voice_model()
writer.load_outline('outputs/outlines/01_why_leads_no_bookings_outline.json')
blog_post, analysis = writer.write_blog_post('outputs/outlines/01_why_leads_no_bookings_outline.json')
print('Done. Check outputs/blog_posts/')
"
Generate all articles in the queue:
python3 -c "
from scrapers.blog_writer import BlogWriter
from pathlib import Path
writer = BlogWriter()
writer.load_voice_model()
for outline_file in sorted(Path('outputs/outlines').glob('*_outline.json')):
print(f'Writing: {outline_file.name}')
blog_post, analysis = writer.write_blog_post(str(outline_file))
print('Done.')
"
Test without spending API credits (mock mode):
python3 test_blog_writer_mock.py
Output lands in outputs/blog_posts/ as .md files, ready to add to the Cloudflare blog worker.
Step 4 — Quality check before publishing
- [ ] Leads with the problem, not the solution
- [ ] Targets a commercial or transactional intent only
- [ ] Does not duplicate an existing intent signature
- [ ] Matches the content format already cited by LLMs for that prompt
- [ ] Uses specific economic language (cost per slot, revenue per session, no-show rate)
- [ ] Editorial truths from the outline are actually in the article
- [ ] Sounds like a consultant, not an agency
- [ ] No forbidden phrases (search for: cutting-edge, painless, amazing, bespoke, free consultation)
- [ ] No em dashes anywhere in the copy
- [ ] CTA says "book a clinical assessment" or "map your booking flow" — never "call us today"
- [ ] Reading level accessible (Grade 8–9 target)
If the article reads like a generic AI blog, the outline's editorial_truth field needs to be sharper. Add more specific, concrete claims then regenerate.
Step 5 — Publish to insights.aureagrowth.co
Blog runs on a Cloudflare Worker at tools/cloudflare-workers/aurea-insights-blog/worker.js.
Adding a new article:
1. Convert the .md draft to clean HTML (use the existing article in worker.js as the format reference)
2. Add a new object to the ARTICLES array in worker.js with: slug, title, meta, tag, tagSub, date, readTime, toc, body
3. Deploy: cd tools/cloudflare-workers/aurea-insights-blog && npx wrangler deploy
First-time domain setup (one-time):
1. Deploy the worker (step 3 above) — it goes live at a *.workers.dev URL first
2. Cloudflare dashboard → Workers and Pages → aurea-insights-blog → Settings → Domains and Routes → Add custom domain
3. Add insights.aureagrowth.co (requires aureagrowth.co DNS managed in Cloudflare)
Adding a second lane blog (johntossou.com/blog or tossouadvisory.com/articles):
Copy the aurea-insights-blog/ folder, change the name in wrangler.jsonc, swap brand tokens in the CSS, update article data. Same pattern, 15 minutes.
Step 6 — Repurpose (the 1 to many system)
Every published article becomes 4 more assets. Do this immediately after publishing while the thinking is fresh.
Instagram carousel (10 min)
5–7 slides. One idea per slide. No paragraphs.
Slide 1: The problem statement (big text, plain background)
Slide 2: Why it happens (one sentence)
Slide 3: What it costs
Slide 4: What the fix looks like
Slide 5: The principle / takeaway
Slide 6: CTA ("Book a clinical assessment")
Every slide 6 pivots from patient education to clinic owner framing. Patients share slides 1–5. Clinic owners see slide 6 and think: that's me.
Short video hook (10 min)
20–40 second script:
Hook (5 sec): the most jarring claim
Problem (10 sec): why it matters
Pattern (10 sec): "we see this every week with clinics that..."
Exit (5 sec): soft CTA or question
Ad hook (5 min)
Pull the pain from the article into a single line. This becomes a headline test for future Meta ads.
Examples:
- "You don't need more leads. You need better patients."
- "Most lost revenue isn't your ads. It's the hour you're closed."
- "Your diary is full. Your revenue isn't growing. This is why."
LinkedIn post (5 min) — not a current priority, but the format:
Pull the sharpest sentence from the article as the hook. Then 3–4 short lines expanding it. End with a question or a quiet CTA.
Repurposing boundaries
- Automate draft generation, formatting, and export where it saves time.
- Keep the insight selection, final framing, and publish/no-publish decision human.
- Do not auto-post raw RSS summaries to social channels.
- Do not let repurposing flatten the original editorial truth into generic motivational content.
5. SEO Strategy
Clinic owners don't search "aesthetic marketing agency UK." They search:
- "why am I getting no shows clinic"
- "meta ads not working aesthetics"
- "how to reduce cancellations dental"
- "why do patients not rebook"
These are the entry points. Every article starts with a real clinic problem, not a keyword.
Teardown content (your unfair advantage)
Mailman audits contain the best SEO content you'll ever produce. The process:
- Do the Mailman audit (you're already doing this)
- Strip the clinic identity
- Keep the insight — the leak, the pattern, the consequence
- Publish as an anonymous pattern breakdown
Example:
"Why discount ads and open booking attract the wrong patients"
Inside: "In a recent clinic we analysed..." — then describe the situation, the leak, the fix.
You keep 100% of the insight. Zero of the risk.
LLM takeover workflow
- Pick a commercial prompt worth owning.
- Search it in Gemini, Perplexity, and ChatGPT.
- Record the cited sources and their format.
- Choose the weakest current winner.
- Build an Aurea page that preserves the winning format but carries sharper economics, stronger operator logic, and clearer qualification thinking.
- Publish fast, then monitor citations and branded search behavior.
What AI content needs to rank
AI content is not penalised by Google. Generic content is.
- Generic: "Here are 5 tips for reducing no-shows"
- Ranking: "A clinic running £15 Meta ads with no deposit requirement loses £33k/quarter in attended-but-didn't-convert slots"
The editorial_truth field in each outline is what separates these. Specific numbers. Real scenarios. Concrete consequences.
6. Brand Voice Rules
Tone: Direct. Punchy. Pain-focused. No jargon.
Rules:
1. Lead with the problem, not the solution. Reader feels seen before being sold to.
2. Short sentences. Short paragraphs. One idea per line.
3. Say it in the first sentence. No preamble or scene-setting.
4. Write how a sharp operator talks to a peer — not how an agency writes a brochure.
Reference: The Aurea Mailman letters — short observational paragraphs, one claim per sentence, pain named before anything else.
Forbidden phrases: cutting-edge, bespoke, industry-leading, omnichannel, synergy, seamless, holistic approach, in today's competitive landscape, leverage, solutions, painless, amazing, free consultation, call us today.
Forbidden punctuation: Em dash (—). It signals AI-generated copy. Rewrite the sentence instead. Replace with a full stop, comma, colon, or bracket.
7. Adding New Insights to the Knowledge Base
When you learn something new — from a client conversation, a Mailman outcome, a Reddit thread, a sales call — add it to research/content-insights-base.md.
The file is structured in 6 parts:
1. Patient psychology (emotional drivers, language, fears, buying triggers)
2. Clinic owner psychology (pain points, agency trauma, decision triggers)
3. The connecting insight (how both sides are solving the same problem)
4. Operational gaps (product opportunities)
5. Content pillars and copy phrases
6. Content strategy and distribution
Add to the relevant section. If you learn a new verbatim phrase patients use, add it to Part 1. If you discover a new clinic owner objection, add it to Part 2. The richer this gets, the better the articles.
8. Article Queue
| # | Title | Pillar | Status |
|---|---|---|---|
| 01 | Why Your Clinic Is Getting Leads But No Bookings | Economics | Ready to generate |
| 02 | The Real Cost of a No-Show | Economics | Ready to generate |
| 03 | Are You a Sinker or a Sagger? | Problem (patient) | Ready to generate |
| 04 | Why Meta Ads Fail for Aesthetic Clinics | Economics | Ready to generate |
| 05 | The 48-Hour Panic After a Skin Booster | Expectation (patient) | Blog + HTML preview done |
| 06 | How to Choose a Safe Aesthetics Clinic in London | Fear (patient) | Ready to generate |
| 07 | Why Most Clinic Open Days Attract the Wrong Patients | Economics | Ready to generate |
| 08 | Why the Best Aesthetic Clinics Make You Wait Before They Inject | Standard | Outline ready |
| 09 | Why Polynucleotides Won't Fix Your Under-Eye Hollows | Fear (patient) | Outline ready |
Suggested next outlines:
- Why your clinic is paying for the wrong patients (discount ads + open diary + no deposit)
- The real cause of no-shows (it's not patients, it's the system)
- After-hours missed calls: the £33k/quarter revenue leak
- Why open booking systems kill high-ticket treatments
- GHL vs Fresha/ANS/Pabau for qualification flows
- The post-treatment WhatsApp check-in (why most clinics skip it and what it costs)
9. Where Everything Lives
| Asset type | Location |
|---|---|
| Market intelligence | research/content-insights-base.md |
| Article outlines | aurea-content-engine/outputs/outlines/ |
| Finished blog posts (markdown) | aurea-content-engine/outputs/blog_posts/ |
| HTML blog previews | aurea-content-engine/outputs/blog_posts/preview_*.html |
| IG carousel previews | aurea-content-engine/outputs/instagram/ |
| Brand config | aurea-content-engine/config.yaml |
| Brand assets (fonts, logo) | /Users/johntossou/Desktop/Aurea Growth/Aurea Growth Branding Kit/ |
| Published blog | insights.aureagrowth.co (Ghost — to be set up) |
10. Connection to Revenue
Mailman letter sent to clinic
↓
Clinic owner Googles "Aurea Growth"
↓
Lands on 5–10 sharp articles that confirm expertise
↓
Replies to Mailman warmer, books call pre-sold
↓
Close rate goes up, sales cycle goes down
SEO inbound is a secondary benefit that kicks in after month 3–4 of consistent publishing.
Primary acquisition channel: Mailman. Content is the trust layer behind it.
10.5 What to automate and what to keep human
Automate:
- keyword clustering
- outline scaffolding
- citation-format reminders
- markdown generation
- image/export formatting
- PageSpeed remediation planning
Keep human:
- editorial truth extraction
- final CTA judgment
- publish decision
- repurposing angle selection
- anything that could change clinical positioning or patient trust
11. Troubleshooting
API key error:
ValueError: ANTHROPIC_API_KEY environment variable not set
Create .env in aurea-content-engine/ with: ANTHROPIC_API_KEY=sk-ant-...
Output is too generic:
The editorial_truth field in the outline is too vague. Add more specific claims — real numbers, real scenarios, real consequences. Regenerate.
Output uses forbidden phrases:
Search for: "cutting-edge", "industry-leading", "painless", "amazing", "bespoke", "free consultation". The system prompt already bans these but the model occasionally slips. Edit manually.
File not found for outline:
Make sure the outline filename ends in _outline.json. The generator globs for that pattern.
Activation Prompt
You are in johntossou.com SEO mode. This lane targets hiring managers, adtech/martech founders, and aesthetics marketers. Read lane-johntossou.md in full. Focus: positioning John as a senior adtech/martech consultant with UK aesthetics vertical expertise. Competition is low — content compounds fast. This lane is the fastest ROI per article published.
Lane: John Tossou Personal Brand
Lane: johntossou.com personal brand
Domain: johntossou.com
Audience: Three distinct groups (see below)
Owner: John — strategy, drafts, publishes
Priority: High — job signal, adtech authority, Aurea cross-pollination, GEO footprint
Status: Site exists. SEO content not yet started. Start here.
Back to: MASTER.md
Why This Lane Matters
Three compounding reasons, each valid independently:
-
Job insurance. With a baby due and Aurea pre-MRR, a content footprint on johntossou.com means hiring managers and headhunters find you before you need them. One well-ranking article on "programmatic advertising UK" or "adtech GTM consultant" puts you in relevant search results passively.
-
Advisory pipeline. Founders and execs Googling UK market entry or adtech consulting find you. This is the inbound layer for JCT Advisory and Tossou Advisory referrals that doesn't require LinkedIn activity.
-
Aurea authority transfer. Every article about aesthetics clinic marketing, GHL workflows, or Google Ads for clinics strengthens Aurea's positioning by proxy. Prospects who Google John Tossou before signing find proof he knows what he's doing.
Audiences
Three audiences, one site — different articles serve different groups.
| Audience | What they search | What they need to see |
|---|---|---|
| Hiring managers / recruiters | "adtech consultant London", "programmatic advertising UK", "GTM strategy UK" | Track record, specific platforms, outcomes |
| Adtech/martech founders considering UK expansion | "UK market entry adtech", "UK adtech GTM", "programmatic UK landscape" | Market knowledge, operator credibility, practical intelligence |
| Aesthetics marketers / clinic owners | "GoHighLevel aesthetics UK", "Google Ads aesthetics clinic", "clinic automation UK" | Practitioner proof, specific results, actionable frameworks |
Keyword Universe
Tier 1 — Job signal (low competition, high hiring-manager intent)
These rank fast because almost no one is writing about them at a personal brand level.
| Keyword | Intent | Notes |
|---|---|---|
| adtech consultant London | Commercial | Direct job/advisory signal |
| programmatic advertising consultant UK | Commercial | Very few competitors at personal brand level |
| UK market entry adtech | Informational/commercial | Founder-audience entry point |
| GTM strategy UK adtech | Commercial | JCT Advisory angle |
| GoHighLevel aesthetics clinic | Informational | Ranks fast — almost no content exists |
| GHL workflows clinic UK | Informational | Same — extremely low competition |
| Google Ads aesthetics clinic UK | Informational/commercial | Direct Aurea service proof |
Tier 2 — Authority and cross-pollination
| Keyword | Intent | Notes |
|---|---|---|
| clinic automation UK | Informational | Bridges adtech and aesthetics audiences |
| aesthetics clinic marketing UK | Commercial | Aurea proof by proxy |
| GHL vs Fresha comparison | Informational | Very searchable, low competition |
| GoHighLevel vs booking systems aesthetics | Informational | Long-tail, zero competition |
| programmatic advertising UK agencies | Commercial | Market overview content |
| adtech UK landscape 2026 | Informational | Authority positioning |
Tier 3 — GEO targets (optimise for AI citation)
These are prompts people are already asking AI tools. Rank here = cited in ChatGPT/Perplexity answers.
- "What is the best CRM for aesthetics clinics?"
- "How to reduce no-shows in a UK aesthetics clinic"
- "GoHighLevel for medical aesthetics — is it worth it?"
- "UK adtech market entry — what to know"
- "How to set up Google Ads for an aesthetics clinic"
Target Pages to Build
Build in this order. Each page targets one intent cluster.
Phase 1 — Foundation (do these first, unlocks job signal)
| Page | URL | Primary keyword | Notes |
|---|---|---|---|
| Home / About | / |
John Tossou adtech consultant | Bio, proof points, three lanes clearly stated |
| Adtech / GTM consulting | /adtech-consulting |
adtech consultant London | JCT Advisory offer, Corvidae / Pixis proof |
| Aesthetics marketing | /aesthetics-marketing |
aesthetics clinic marketing UK | Aurea proof, NK / Elhama / BrightSmile outcomes |
Phase 2 — Blog articles (compounds over time)
| Article | Primary keyword | Pillar | Priority |
|---|---|---|---|
| Why Google Ads beats Meta for premium aesthetics clinics | Google Ads aesthetics clinic UK | Practitioner | High |
| GoHighLevel vs Fresha: which is better for UK aesthetic clinics | GHL vs Fresha aesthetics | Comparison | High |
| How we reduced cost-per-consultation for a North London aesthetics clinic | aesthetics clinic Google Ads case study | Proof | High |
| What adtech companies get wrong about UK market entry | UK market entry adtech | Authority | High |
| GoHighLevel setup guide for aesthetics clinics (the non-technical version) | GoHighLevel aesthetics clinic setup | Practitioner | Medium |
| Why clinic automation starts with intake, not marketing | clinic automation UK | Practitioner | Medium |
| The GHL workflow stack that actually works for a solo aesthetics practitioner | GHL workflows clinic | Practitioner | Medium |
Content Angles
These angles apply across all articles on johntossou.com.
Practitioner teaching practitioners. Every article is written by someone who has run real campaigns and seen real outcomes — not an agency pitching services. "Here is what happened, here is the exact number, here is what I would do differently."
Specificity over breadth. A post titled "How we cut CPA from £467 to £89 for a North London under-eye treatment clinic over 90 days" is worth 10 generic "how to run Google Ads" posts for both SEO (low competition) and GEO (AI models love specific, citable numbers).
Comparison content. "GHL vs Fresha", "Google Ads vs Meta for aesthetics", "Appointwise vs manual triage" — comparison posts rank fast, get cited by AI tools, and are directly useful to the Aurea prospect audience.
UK-specific operator intelligence. Most adtech and clinic marketing content is US-written. CQC compliance, GHL setup for UK numbers, UK carrier rules for WhatsApp Business — none of this exists in useful form. First-mover advantage is real here.
Brand Voice for johntossou.com
Different to Aurea's agency voice. Slightly more personal — this is John as an operator, not as an agency brand.
Tone: Direct. Specific. No preamble. Practitioner-to-practitioner.
Lead with the outcome or the problem: "We cut cost per consultation by 81% in 90 days. Here is exactly how." Not "In this article I will share..."
Permitted first-person: "I built", "we ran", "I tested", "here is what I found" — this is a personal brand, first-person is appropriate and builds trust.
Forbidden (same as Aurea): Em dashes, cutting-edge, bespoke, industry-leading, seamless, leverage, solutions.
No agency speak. This is not a pitch document. No "if you're looking to transform your clinic's performance..." — just direct practitioner language.
CTA Structure
Every article on johntossou.com routes to one of three destinations depending on the reader's likely intent:
| Reader type | CTA | Destination |
|---|---|---|
| Hiring manager | "See my background" | LinkedIn or CV page |
| Adtech founder / exec | "Talk about UK market entry" | Contact form (JCT Advisory angle) |
| Clinic owner / aesthetics marketer | "See what Aurea Growth does" | aureagrowth.co |
Use the reader's intent to pick the right CTA. Don't use the same CTA on every page.
Publishing Setup
Platform: johntossou.com (existing site — check CMS before deciding on blog setup)
Blog path: /blog or /insights — keep it separate from service pages
Schema to add on every post:
- Article schema (author: John Tossou, credentials listed)
- Organization schema (John Tossou / JCT Advisory)
- BreadcrumbList
Meta format:
- Title: [Specific outcome or claim] | John Tossou
- Description: 145-155 characters, lead with the specific number or claim
No stock photos. Real screenshots, real campaign data (anonymised where needed), real clinic dashboards.
Article Brief Template
Use brief-template.md for every article. Set lane: johntossou and pick the right audience from the three groups above.
Progress Tracker
| Page / Article | Status | Published URL | Notes |
|---|---|---|---|
| Home / About | Not started | — | — |
| Adtech consulting page | Not started | — | — |
| Aesthetics marketing page | Not started | — | — |
| Google Ads vs Meta for aesthetics | Not started | — | — |
| GHL vs Fresha comparison | Not started | — | — |
| NK case study (Google Ads + CPA) | Not started | — | Anonymise client details |
| UK market entry adtech post | Not started | — | — |
Activation Prompt
You are in Tossou Advisory SEO mode. Low priority lane. Read lane-tossou-advisory.md before touching anything. Domain: tossouadvisory.com. Audience: French-speaking Series B CEOs/CFOs. Owner: John + Dan. Only produce content here when explicitly asked — do not generate unprompted.
Lane: Tossou Advisory
Lane: Tossou Advisory brand
Domain: tossouadvisory.com
Audience: French-speaking Series B CEOs, CFOs, CMOs, founders considering UK-France expansion
Owner: John (commercial content), Dan (finance content)
Priority: Low — narrow audience, slow compounding, no time pressure
Status: Site exists. SEO content not started. Start after johntossou.com Phase 1 is live.
Back to: MASTER.md
Why This Lane Is Different
Every other lane targets English-speaking, Google-searchable audiences. This lane is French-speaking B2B with very specific needs. The audience is small but extremely high-value — one inbound lead from this lane is worth more than 50 aesthetics clinic leads.
Two implications:
1. Volume does not matter. Rank for 5 highly specific French-language queries and you own the lane. You do not need 50 articles.
2. Compounding is slow. French-language SEO for UK advisory services is a 12-24 month play. Do not expect organic traffic before then. The content exists to be found when someone is already in the research phase — not to generate cold volume.
Start building this lane only after johntossou.com has at least 3 articles live.
Audience
A French-speaking Series B CEO or founder who is:
- Considering UK expansion (from France, Belgium, Switzerland, or Canada)
- Navigating a commercial or financial decision that has UK implications
- Skeptical of generic consultants who pitch strategy decks without accountability
- Looking for an independent view that isn't paid by the agency or vendor they're evaluating
The site's positioning is buyer-side only. No commissions, no referral fees, no pay-to-play. This is the differentiator and it must come through in every piece of content.
Keyword Universe
French-language (primary)
| Keyword | Intent | Notes |
|---|---|---|
| expansion marché UK | Informational/commercial | High-intent entry point for founders |
| entrée marché royaume-uni | Informational | Alternative phrasing for same intent |
| consultant expansion UK France | Commercial | Direct advisory search |
| direction commerciale externalisée UK | Commercial | JCT Advisory service directly |
| direction financière externalisée UK | Commercial | Dan's service directly |
| advisory UK France | Commercial | Bilingual search — some leads search in English |
| développement commercial UK | Commercial | Broader but relevant |
| conseil expansion internationale startup | Commercial | Startup audience, Series A-B |
| marché UK adtech | Informational | Niche — adtech founders only |
English-language (secondary — French founders often search in English for UK content)
| Keyword | Intent | Notes |
|---|---|---|
| UK market entry France | Informational/commercial | French companies Googling in English |
| UK expansion consultant France | Commercial | Direct advisory intent |
| fractional CCO UK France | Commercial | Some audience uses this term |
| UK commercial development France | Commercial | Less competitive than "UK market entry" |
Target Pages
Very few pages needed. The audience is narrow. Quality over volume.
Phase 1 — Foundation
| Page | URL | Language | Primary keyword | Notes |
|---|---|---|---|---|
| Home | / |
French | consultant UK-France | The "Décider avant de dépenser" positioning page |
| Decision Diligence | /diligence-de-decision |
French | conseil décision UK | Format Court explanation |
| Externalised Direction | /direction-externalisee |
French | direction commerciale externalisée | Format Continu explanation |
| Contact | /contact |
French | — | Simple, no pitch |
Phase 2 — 3-5 long-form articles
| Article | Language | Primary keyword | Pillar |
|---|---|---|---|
| Les 5 erreurs des entreprises françaises qui entrent sur le marché UK | French | expansion marché UK erreurs | Education |
| Comment choisir un partenaire commercial UK sans se faire rouler | French | choisir partenaire commercial UK | Comparison/authority |
| UK vs France: ce que les fondateurs ne savent pas avant d'y aller | French | différences marché UK France | Education |
| Ce que coûte vraiment une entrée marché UK mal préparée | French | coût expansion UK | Economics |
Content Rules for This Lane
Language: French primarily. Use formal but direct French — this is a senior executive audience, not startup Twitter. Do not use anglicisms unnecessarily, but do not avoid English terms that are standard in the business world (KPI, go-to-market, due diligence).
Tone: Sober, senior, buyer-side. The site language rules from TOSSOU-ADVISORY-SITE-STRATEGY.md apply to all content.
Vocabulary to use:
- Direction externalisée
- Direction commerciale / direction financière
- Binôme senior
- Mission continue
- Diligence de décision
- Présence terrain
- Buyer-side
- Indépendance
Vocabulary to avoid:
- Fractional CFO, fractional CRO, fractional CMO (US startup language, wrong register)
- Growth advisor, unlock your potential (overblown)
- Transformational, world-class, elite (same)
- Em dashes in French or English (same rule as all lanes)
GEO note: French-language GEO is less competitive than English. Well-structured French content with entity clarity, FAQ schema, and direct answers can appear in French AI Overview results faster than equivalent English content. Prioritise the Quick Summary block and structured FAQ on every page.
CTA Structure
One CTA only: contact for an initial conversation.
No pricing on the site (per site strategy). No self-service booking. The CTA is always:
"Prenez contact pour un premier échange."
Route to a contact form or email. No calendly-style booking — too informal for this audience.
Publishing Setup
Platform: Cloudflare Worker (existing — see tools/cloudflare-workers/johntossou-advisory-landing/)
Blog path: Add /insights or /articles section when Phase 2 content is ready
Schema on every page:
- Organization schema (Tossou Advisory / JCT Advisory LTD)
- WebPage schema
- French-language hreflang tag
Meta format (French):
- Title: [Service or claim] | Tossou Advisory (max 60 characters in French)
- Description: 145-155 characters in French
Article Brief Template
Use brief-template.md for every article. Set:
- lane: tossou-advisory
- language: fr
- audience: French-speaking Series B CEOs / CFOs
Progress Tracker
| Page / Article | Status | Published URL | Notes |
|---|---|---|---|
| Home | Exists (Cloudflare Worker) | tossouadvisory.com | Review SEO meta and schema |
| Decision Diligence page | Not started | — | — |
| Externalised Direction page | Not started | — | — |
| Les 5 erreurs des entreprises françaises | Not started | — | — |
| Comment choisir un partenaire commercial UK | Not started | — | — |
Activation Prompt
You are in AI Systems mode. Read docs/Doc Business/clinic-omnichannel-ai-stack-playbook.md and docs/vapi-ghl-best-practices-2026-03-31.md before touching any setup. Stack: GHL + Vapi + Appointwise + n8n + WhatsApp Business API. Critical: Vapi fires multiple webhook events per call — filter by end-of-call-report only. GHL loop lock prevention is mandatory. Vapi native GHL OAuth connector is broken as of 2026-05 — use the Cloudflare webhook bridge.
Clinic Omnichannel AI Stack — Decision Playbook
Last updated: 2026-05-06
Source client: Elhama Beauty Boutique (setup April 2026)
This document captures every decision, constraint, failure mode, and architecture pattern from building a full omnichannel AI system for a UK aesthetics clinic. Use it at the start of every new client engagement to avoid re-learning the same lessons.
What This Stack Does
A single system that:
- Handles all inbound messages (WhatsApp, Instagram DM, Facebook DM, SMS) via AI triage
- Handles all inbound phone calls via an AI voice agent using the clinic's own cloned voice
- Stores every interaction in a CRM, logs calls, extracts contact details automatically
- Lets the clinic owner see everything in one inbox without touching a phone
Stack Components
| Tool | Role | Required? |
|---|---|---|
| GHL (GoHighLevel / LeadConnector) | Unified inbox, CRM, workflows, WhatsApp Business API, Instagram/Facebook DMs, contact management | Always |
| Appointwise | AI triage agent for chat channels (WhatsApp, Instagram, Facebook, SMS). Sits on top of GHL. | Yes for chat AI |
| Vapi | AI voice agent for inbound phone calls. Handles call, collects details, generates transcript + summary | Yes for voice AI |
| Twilio | Phone number infrastructure. Buy numbers here. Vapi connects via Twilio. | Yes (via Vapi) |
| ElevenLabs | Voice cloning. Clone the owner's voice and assign it to the Vapi agent | Yes if voice clone needed |
| n8n | Automation bridge for complex logic between systems | Optional — not needed for v1 |
| Meta Business Manager | Required to connect Instagram DMs and Facebook DMs to GHL | Yes if using Meta channels |
Channel Coverage — What Is and Is Not Possible
| Channel | AI Triage | Notes |
|---|---|---|
| WhatsApp messages | Yes | Via GHL WhatsApp Business API + Appointwise |
| Instagram DMs | Yes | Via Meta Business Portfolio connected to GHL |
| Facebook DMs | Yes | Via Meta Business Portfolio connected to GHL |
| SMS (inbound) | Yes | Via GHL LC Phone number |
| Inbound phone calls | Yes | Via Vapi + carrier forwarding |
| WhatsApp voice calls | No | Hard technical limit — see below |
| Outbound SMS follow-up post-call | Yes, with conditions | Requires LC Phone number with SMS capability |
WhatsApp Voice Calls — Hard Limit
When a number is connected to WhatsApp Business API, it cannot receive WhatsApp in-app voice or video calls. The call shows as failed or dropped on the caller's screen. GHL sees nothing — no notification, no contact record created. This cannot be fixed technically.
Mitigation:
1. Add a note to the business WhatsApp bio: "For calls, please use the regular phone number. For messages, WhatsApp us here."
2. Send a broadcast to existing contacts before go-live explaining the change
3. First-message GHL automation: when a new contact messages, the opening reply includes "If you tried to call via WhatsApp and it didn't connect, please call [number] directly."
Accept this as a trade-off. The client must understand it before the number goes live on the API.
The "Same Number" Problem
Every clinic wants one number that does everything. Here is the reality:
| What they want | What is actually possible |
|---|---|
| 07501 914514 handles WhatsApp messages | Yes — connect to GHL WhatsApp Business API |
| 07501 914514 receives carrier calls and Vapi picks up | Yes — set carrier forwarding to Vapi number |
| 07501 914514 receives WhatsApp voice calls | No — hard limit, see above |
| SMS sent back to caller from same Vapi number | Depends on number capability — see below |
| One number for everything | Achievable for 3 of the 4 above |
Number architecture in practice:
The client keeps their existing mobile number (e.g. 07501 914514). It gets two roles:
1. Connected to GHL WhatsApp Business API — handles all messages
2. Carrier-level call forwarding to a separate Twilio/Vapi number — handles all calls
The Vapi number is a separate UK number (e.g. +44 1923 311259) bought in Twilio. Callers dial the clinic number, get forwarded, and Vapi answers.
Client dials 07501 914514
|
├── Carrier-level forwarding → +44 1923 311259 (Vapi)
| Vapi answers, collects details, logs to GHL
|
└── WhatsApp message → GHL inbox → Appointwise AI triage
Call Forwarding — Unconditional vs Conditional
Two options. Decide with the client.
| Type | Behaviour | Use case |
|---|---|---|
| Conditional (busy / no answer) | Vapi picks up only if the owner doesn't | Owner wants to answer sometimes |
| Unconditional (always forward) | Vapi always answers, owner never picks up | Owner is always working and cannot answer |
For clinics like Elhama: unconditional is almost always the right call. Owner-operators doing hands-on treatments physically cannot break to take calls.
Unconditional forwarding dial codes (UK carriers):
- All carriers: **21*+441923311259# (replace with actual Vapi number)
- To cancel: ##21#
Confirm the client's carrier before go-live — codes vary slightly.
Voice AI — GHL Native vs Vapi
| Option | Status | Notes |
|---|---|---|
| GHL Native Voice AI | Unreliable in production (tested April 2026) | Call forwarding failed in production on tested GHL numbers. Not ready for live client use. Review again after 30+ days. |
| Vapi | Reliable, production-tested | Preferred for all live client voice work. Connects via Twilio. Full transcript, recording, structured data extraction. |
Decision: always use Vapi for voice in v1. Revisit GHL native at 30 days.
Voice Cloning with ElevenLabs
When to do it: at the first in-person meeting, once the client has seen the system and trusts it enough to want their voice on it.
Process:
1. Client reads a 2-minute script (natural, conversational — not a formal read)
2. Record audio (phone voice memo is fine)
3. Upload to ElevenLabs → Instant Voice Clone → name it clearly
4. Copy the voice ID
5. PATCH the Vapi assistant: {"voice": {"provider": "11labs", "voiceId": "VOICE_ID"}}
What to expect: the clone will not be perfect on the first attempt. The client may describe it as "too fast" or "too English" — this is a prompt issue as much as a voice issue. Soften the system prompt alongside the voice change.
System prompt tone for clinic voice agents:
- Warm, unhurried, conversational UK English
- One question at a time — never stack questions
- Use connectors: "Of course", "No worries at all", "That sounds lovely", "Absolutely"
- Frame photo review / qualification as a caring personal touch, not a barrier
- Never invent pricing, availability, or clinical advice
Vapi → GHL Integration
Vapi does not natively sync with GHL. The bridge is a GHL Inbound Webhook workflow.
Architecture
Vapi call ends
↓
Vapi fires end-of-call-report webhook → GHL Inbound Webhook trigger
↓
GHL workflow runs:
1. Create/Update Contact (phone number)
2. Log External Call (direction, status, recording URL)
3. (optional) Send SMS / WhatsApp follow-up
Structured Data Extraction
Vapi can extract structured fields from every call automatically. Configure via analysisPlan.structuredDataSchema on the assistant:
{
"analysisPlan": {
"structuredDataSchema": {
"type": "object",
"properties": {
"callerName": {"type": "string"},
"callerEmail": {"type": "string"},
"callerPhone": {"type": "string"},
"treatmentInterest": {"type": "string"}
}
},
"structuredDataPrompt": "Extract caller name, email, phone number stated during call, and treatment interest. Leave blank if not mentioned."
}
}
These fields appear in the webhook payload at message.analysis.structuredData.* and can be mapped directly in GHL workflow actions.
GHL Workflow — Critical: Loop Lock Prevention
Problem: Vapi fires multiple webhook events per call (status-update, transcript, assistant-request, end-of-call-report — typically 6–10 events per call). If all hit the GHL workflow, it runs 10+ times per call. GHL detects this as a loop (threshold: 50 workflow starts per contact in 30 minutes) and auto-locks the workflow to Draft. Even a NO-branch exit counts as a start, so an If/Else filter inside GHL alone is not enough once test volume builds.
Fix — two steps, in this order:
Step 1 (do first — eliminates the problem at source): Vapi dashboard → your assistant → Advanced → Server Messages → set to ["end-of-call-report"] only. Vapi stops sending all intermediate events. GHL never sees them. This must go in before the workflow is republished.
Note:
serverMessagesfilter only works on Vapi Assistants — not Vapi Workflows.
Step 2 (secondary safeguard): Add an If/Else branch as the first action after the Inbound Webhook trigger:
- Condition: {{message.type}} equals end-of-call-report
- Yes branch: all actions (Create Contact, Log Call, field mappings) run here
- No branch: workflow ends immediately
Never publish the GHL webhook workflow without both fixes in place.
If the workflow gets loop-locked: contact GHL support via live chat and say "Our inbound webhook workflow was auto-locked to Draft due to loop detection. We have identified the root cause and have a fix ready. Please unlock the workflow so we can re-publish it." GHL will unlock it manually — their senior support team can do this. Do not attempt to republish before the Vapi serverMessages filter is set.
GHL Workflow — Field Mapping Reference
Confirmed working paths. Do NOT use common wrong guesses — they silently map nothing.
| GHL Field | Vapi Payload Path | Notes |
|---|---|---|
| Contact Phone | {{message.call.customer.number}} |
|
| Contact First Name | {{message.analysis.structuredData.callerName}} |
Requires structuredDataSchema on assistant |
| Contact Email | {{message.analysis.structuredData.callerEmail}} |
|
| Custom — treatment interest | {{message.analysis.structuredData.treatmentInterest}} |
|
| Custom — call summary | {{message.summary}} |
|
| Custom — transcript | {{message.artifact.transcript}} |
NOT message.transcript — that path does not exist |
| Custom — recording URL | {{message.artifact.recording.recordingUrl}} |
NOT message.recordingUrl or message.artifact.recordingUrl |
| Custom — call outcome | manual dropdown | no direct Vapi field — set after human review |
| Log Call — Direction | inbound (hardcoded) |
|
| Log Call — From | Vapi UK number (hardcoded, e.g. +441923311259) |
|
| Log Call — To | {{message.call.customer.number}} |
|
| Log Call — Status | completed (or map from {{message.endedReason}}) |
|
| Log Call — Attachment (recording) | {{message.artifact.recording.recordingUrl}} |
same corrected path as above |
Do not map message.durationSeconds — this field does not exist in the Vapi end-of-call-report payload. Derive duration from call.startedAt / call.endedAt if needed later.
Re-entry Setting
Set the workflow re-entry to Allow every time. Every call must run the workflow, not just the first one per contact.
SMS Follow-up After Call
Constraint: UK Twilio local numbers often do not support SMS. Always check the number's capabilities in Twilio before assuming SMS is available. In the Configure tab, if you see "Messaging configuration is unavailable for this phone number" — SMS is not possible from that number regardless of GHL settings.
Options:
| Option | When to use |
|---|---|
| GHL LC Phone number (separate number) | Fastest to set up. SMS comes from a different number but message identifies the clinic. |
| Twilio Connect (connect existing Twilio account to GHL LC Phone) | Preferred for future clients. Lets GHL use numbers from your Twilio account for SMS. Requires GHL to confirm whether it conflicts with Vapi using the same number simultaneously. |
| WhatsApp template message post-call | Cleanest option. Once the client's number is on WhatsApp Business API, send a WhatsApp follow-up from their own number. Requires a pre-approved message template. Available after go-live. |
| Full number migration to GHL | Avoid. Moves the number out of your Twilio account, breaking Vapi. |
Recommended for v1: skip SMS entirely. Add WhatsApp follow-up as a post-go-live workflow action using the client's main number.
Twilio Number Buying — What to Check
Before buying a Twilio number for any client:
- Capabilities — confirm Voice AND SMS are listed under Capabilities in Twilio console. UK local numbers (01xxx / 02xxx) often do not support SMS. UK mobile-style numbers (07xxx) usually do.
- Regulatory bundle — UK numbers require a Regulatory Bundle with an approved address. Create this before buying if it doesn't already exist.
- Messaging capability — after buying, check the Configure tab. If "Messaging configuration is unavailable" appears, you cannot send SMS from that number.
Meta / Instagram / Facebook Setup
What is needed
- Client grants access to their Meta Business Portfolio (Business Manager)
- Facebook Page must be connected to the portfolio
- Instagram account must be switched to Professional and linked to a Facebook Page
- GHL must be approved as a messaging integration in Meta Business Suite
- All accounts must show "Connected" in GHL → Settings → Integrations
Critical visibility rule for GHL
For Meta-connected channels, Business Portfolio ownership alone is not enough.
The final gate that controls which Pages / Instagram accounts are actually visible to GHL is usually the Facebook login that authenticated LeadConnector:
Facebook -> Settings & privacy -> Business integrations -> LeadConnector -> View and edit
This is where the connected Facebook user can expose or hide the assets available to GHL.
If an account looks correctly connected in Meta but still does not appear in GHL:
1. Log into the exact Facebook user that connected LeadConnector
2. Open Settings & privacy -> Business integrations
3. Open LeadConnector -> View and edit
4. Confirm the correct Pages / Instagram accounts are enabled
5. Reconnect or refresh the Facebook/Instagram connection inside GHL if needed
Treat this as a first-line debug step on every clinic setup.
Common blockers
| Blocker | Fix |
|---|---|
| Instagram shows "Login needed" in Meta | Client must log into Instagram and reconnect the account |
| 2FA sent to an old/unavailable phone | Find which phone holds the 2FA. That person must be physically present with the device to complete the connection. |
| Business partner's account linked to wrong number | Same — the account holder must be present with the registered device |
| Instagram not linked to a Facebook Page | Switch to Professional account first; Instagram prompts to create or link a Page during that process |
Multi-account setup (e.g. business partner with separate Instagram)
If a client has a business partner with a separate Instagram driving traffic:
1. Add the partner's Instagram to the client's Meta Business Portfolio (Business Settings → Instagram Accounts → Request Access)
2. Connect as a second Instagram channel in GHL
3. The same Appointwise agent handles both — the partner does not need to do anything operationally
Requires the partner's agreement and Meta page access.
Important: even after the Page + Instagram are correctly linked in Meta, the second account may still stay invisible in GHL until the Facebook user who connected LeadConnector enables that asset in Business integrations -> LeadConnector -> View and edit.
WhatsApp Business API Registration
Pre-registration requirements
- Meta Business Portfolio must be verified. Go to
business.facebook.com→ Settings → Security Center → Business Verification. Status must show Verified before GHL can register any number. Verification takes 2–5 business days after submitting documents. - Correct legal name in Meta. The legal business name entered in Meta Business Manager must match the Companies House certificate exactly — including "Limited." Any mismatch causes rejection.
- Full address required. The address field in Meta Business Manager must contain the full registered address, not just "United Kingdom."
- Primary document for UK businesses: Certificate of Incorporation from Companies House. Free to download. Covers both legal name and registered address. A utility bill alone is not accepted for the legal name — it can only supplement for address/phone verification.
- Identity verification: Meta also requires a personal ID from the company director to complete verification. Passport is preferred. This must be done in person — the director must be physically present to upload their ID.
- The phone number must be in an active SIM on the day of registration (Meta sends an OTP via SMS or voice call).
The number must be released from the WhatsApp Business App first
A phone number cannot be registered on the WhatsApp Business API while it is active on the WhatsApp Business App. This is the most common cause of the "account locked" error in GHL.
Fix: the client must delete their WhatsApp Business App account from within the app before the API registration can proceed. Uninstalling the app alone is not sufficient — the account deletion must happen inside the app.
Steps:
1. Open WhatsApp Business App on the client's phone
2. Settings → Account → Delete my account → confirm
3. Wait 5 minutes for Meta's servers to deregister the number
4. Then proceed with GHL registration
Important: warn the client that this creates a downtime window of approximately 20–30 minutes. Plan it for a quiet period — not mid-clinic.
GHL registration sequence (embedded signup via 360dialog)
- GHL Settings → WhatsApp → Connect a new number
- Log in with the Facebook account that has Business Manager Admin access to the Meta Business Portfolio
- Select the correct business portfolio
- Enter the phone number in international format: +447XXXXXXXXX — never with a leading 0
- Choose Voice Call for OTP delivery (more reliable than SMS for UK O2 numbers)
- Client receives call on their phone, reads out the 6-digit code
- Enter the code in GHL
- Set display name (trading name the client wants customers to see)
- Test immediately — send a message to the number from a separate phone and confirm it appears in the GHL inbox
What the client loses when the number goes on the API
- WhatsApp in-app voice and video calls (hard technical limit — see above)
- The number is no longer usable on the WhatsApp Business App
What the client gains
- Unified inbox in GHL — all WhatsApp messages centralised
- AI triage via Appointwise
- Broadcast campaigns to opted-in contacts
- Automated follow-up workflows
Common errors and fixes
| Error | Cause | Fix |
|---|---|---|
| "Account locked" | Meta Business Portfolio not verified, OR number still active on WhatsApp App | Check verification status in Security Center first; if verified, ensure client has deleted WhatsApp App account |
| "Number already registered" | Account deletion not fully processed | Wait 10 more minutes, retry |
| OTP not arriving | SMS blocked by carrier | Switch to Voice Call option |
| Documents rejected | Legal name mismatch between Meta and Companies House | Check exact name — must include "Limited" if that is the registered name |
One-time WhatsApp history import: during setup, GHL supports importing up to 6 months of WhatsApp Business history. This is a one-time process — do it at setup, not after.
Contact Data Migration
Before connecting any live number:
1. Export contacts from all devices (iPhone via iCloud → .vcf, Android via Google Contacts)
2. Merge and deduplicate
3. Import into GHL subaccount
Do not migrate the live number until the contact import is done. Some CRMs treat number connection as a trigger for history import — doing it in the wrong order risks losing data.
Go-Live Order
Always follow this sequence. Do not shortcut it.
- Export and import contacts into GHL subaccount
- Build and test the AI triage agent (Appointwise) on a separate test WhatsApp number — not the live number
- Run 3-7 days internal stress testing on the test line
- Refine AI tone, photo timing, pricing handling, and handoff rules from test chats
- Set up and test Vapi voice agent independently — call the Vapi number directly
- Validate Vapi → GHL webhook end to end (contact created, call logged, structured data populated)
- Connect Instagram and Facebook DMs — confirm Meta permissions first
- Register live WhatsApp number on GHL only when test line is stable
- Set carrier call forwarding to Vapi number only after WhatsApp is live and tested
- Run full end-to-end test across all channels
- Go live — AI qualifies, human books manually for v1
- Set up Stripe recurring billing — only charge when full system is live
Appointwise Setup Notes
- One Appointwise agent can handle multiple channels in the same GHL subaccount (WhatsApp, Instagram, Facebook, SMS)
- Trigger pattern for v1:
Customer Replied → apply AW-Active-[ClientName] tag - Stop logic at photo / qualification stage: handle in CTA and prompt instructions, not a separate trigger
- Fixed prices,
fromprices, and consultation-led pricing all handled in the prompt and knowledge base - Multilingual: instruct the AI to mirror the lead's language
Billing Setup
- Never start billing before the full system is live and tested
- Agreed billing trigger: all channels live, tested, and client has seen the system working
- Standard: Stripe recurring, £250/month, auto-debit
- Keep a clear written record of the agreed go-live date and billing start date
Common Failure Modes
| Failure | Root Cause | Fix |
|---|---|---|
| GHL workflow loop-locked | Vapi fires 6–10 events per call; GHL counts each workflow start toward the 50/30min lock threshold | Step 1: set Vapi serverMessages to ["end-of-call-report"] only (eliminates events at source). Step 2: add {{message.type}} = end-of-call-report If/Else filter as first GHL action. Both required. |
| Workflow re-locks after republish | Vapi serverMessages not set before republishing — GHL still gets hit with all intermediate events | Set Vapi serverMessages filter FIRST, then republish GHL workflow. Order matters. |
| Transcript or recording URL not mapping | Using wrong payload paths (message.transcript, message.recordingUrl) |
Use {{message.artifact.transcript}} and {{message.artifact.recording.recordingUrl}} — the outer artifact wrapper is required |
| Contact created but name/email missing | Structured data not configured on Vapi assistant | Add analysisPlan.structuredDataSchema to Vapi assistant, map fields in GHL Create Contact action |
| SMS action fails in GHL | No LC Phone number in subaccount, or Twilio number doesn't support messaging | Check Twilio capabilities first; buy LC Phone number or use WhatsApp template instead |
| Vapi not answering calls | Server URL not set on Vapi assistant | PATCH {"serverUrl": "GHL_WEBHOOK_URL"} on the Vapi assistant record |
| Instagram DMs not routing | Instagram account not connected or shows "Login needed" | Client must reconnect Instagram login in Meta Business Manager |
| 2FA blocks Meta connection | 2FA registered to an unavailable phone (old number, old device) | Find who holds the registered number; that person must be present with the device |
| Voice agent sounds rushed / too formal | Default voice + generic prompt | Clone client's voice via ElevenLabs; rewrite prompt with warm UK connectors, one question at a time |
| WhatsApp calls dropping silently | Number on WhatsApp Business API — cannot receive WA calls | Explain to client, add bio note, send pre-go-live broadcast |
| Carrier forwarding not working | Wrong dial code for carrier, or number not on compatible carrier | Confirm carrier, get exact code, test with a second phone before go-live |
Vapi + GoHighLevel Best Practices
Plain-English reference for what we learned while testing Vapi with GoHighLevel / LeadConnector.
Last updated: 2026-04-07
Production Findings — Elhama Beauty (2026-05-04)
This section documents what was discovered and fixed during the live Elhama Beauty Vapi → GHL setup. These are production-validated findings, not theory. Apply them to every future client using this stack.
Critical: Vapi fires multiple webhook events per call
By default, Vapi sends every event type to the server URL — not just the final end-of-call-report. Events fired per call include:
assistant-requeststatus-updatetranscriptfunction-callhangend-of-call-report
All fire to the same URL within the same second. GHL runs the workflow once per event. On a single call, the same contact gets enrolled 6–10+ times in 2 seconds. GHL's loop detection locks the workflow at 50 starts per contact within 30 minutes.
This will happen on every new Vapi → GHL client if not fixed before the first test call.
Fix 1 — Set serverMessages on the Vapi assistant (do this first)
The serverMessages field on the Vapi Assistant object controls which event types fire to the server URL. Set it to only end-of-call-report before pointing any GHL workflow at the assistant.
"serverMessages": ["end-of-call-report"]
Via API:
curl -X PATCH "https://api.vapi.ai/assistant/{assistantId}" \
-H "Authorization: Bearer {VAPI_PRIVATE_KEY}" \
-H "Content-Type: application/json" \
-d '{"serverMessages": ["end-of-call-report"]}'
Via dashboard: Assistant → Advanced → Server Messages → select end-of-call-report only.
Important: serverMessages only works on Vapi Assistants. It does not work on Vapi Workflows. If using a Vapi Workflow, filter at a middleware layer (n8n, Make, or a small relay script) before the payload reaches GHL.
Fix 2 — GHL loop lock mechanics
GHL locks a workflow when it reaches 50 starts for the same contact within 30 minutes. "Starts" counts every workflow entry — including ones that exit immediately via a NO branch on an If/Else filter. The filter inside GHL reduces processing but does not prevent the lock. The only clean fix is suppressing events at the Vapi level via serverMessages.
The If/Else filter on message.type is still worth adding as a secondary safeguard, but it is not a substitute for serverMessages.
Fix 3 — GHL mapping reference must be set before building actions
When creating a new Inbound Webhook workflow in GHL, GHL requires a mapping reference payload before any field variables are available in the workflow builder. Without it, all mapped fields return empty and Create Contact errors with "no value was found for any of the mapped fields."
Correct order:
1. Create the workflow and copy the webhook URL
2. Send a sample end-of-call-report payload to that URL (via curl or a test call)
3. Go back to the trigger settings → Mapping Reference → Check for new requests → select the payload
4. Only then build the action steps
If you build actions before setting the mapping reference, the variable picker will either be empty or suggest incorrect paths. Re-select the mapping reference and re-map each field.
Sample payload to send for mapping reference setup:
curl -X POST "{GHL_WEBHOOK_URL}" \
-H "Content-Type: application/json" \
-d '{
"message": {
"type": "end-of-call-report",
"endedReason": "customer-ended-call",
"summary": "Test call summary.",
"artifact": {
"transcript": "AI: Hello.\nUser: Hi.",
"recording": {
"recordingUrl": "https://storage.vapi.ai/sample.mp3",
"stereoRecordingUrl": "https://storage.vapi.ai/sample-stereo.mp3"
}
},
"analysis": {
"structuredData": {
"callerName": "Test User",
"callerEmail": "test@example.com",
"callerPhone": "+447911000000",
"treatmentInterest": "Brow Treatment",
"callOutcome": "Booking Inquiry"
}
},
"call": {
"id": "sample-001",
"customer": { "number": "+447911000000" },
"startedAt": "2026-05-04T14:00:00.000Z",
"endedAt": "2026-05-04T14:03:30.000Z"
}
}
}'
Fix 4 — Corrected Vapi end-of-call-report field paths
The following paths are production-confirmed from the Vapi end-of-call-report payload. GHL prefixes all webhook fields with inboundWebhookRequest. in the variable picker.
| Field | Correct GHL variable | Common mistake |
|---|---|---|
| Caller phone | {{inboundWebhookRequest.message.call.customer.number}} |
message.phoneNumber.number does not exist |
| First name | {{inboundWebhookRequest.message.analysis.structuredData.callerName}} |
— |
{{inboundWebhookRequest.message.analysis.structuredData.callerEmail}} |
— | |
| Treatment interest | {{inboundWebhookRequest.message.analysis.structuredData.treatmentInterest}} |
— |
| Call summary | {{inboundWebhookRequest.message.summary}} |
— |
| Transcript | {{inboundWebhookRequest.message.artifact.transcript}} |
message.transcript does not exist at top level |
| Recording URL | {{inboundWebhookRequest.message.artifact.recording.recordingUrl}} |
message.recordingUrl does not exist at top level |
| Ended reason | {{inboundWebhookRequest.message.endedReason}} |
— |
| Event type | {{inboundWebhookRequest.message.type}} |
— |
| Duration | Does not exist as a standalone field | Derive from call.startedAt / call.endedAt |
structuredData fields only populate if analysisPlan.structuredDataPrompt and a JSON schema are configured on the Vapi assistant. Verify with a test call payload before relying on them.
Fix 5 — Vapi native GHL OAuth connector is broken (as of 2026-05)
The official Vapi MCP OAuth connector for GHL has been reported broken for months. Users report silent credential errors and 500/502 responses even when Vapi logs show tools triggering correctly. Do not attempt to use the native connector. Use the custom Inbound Webhook workflow approach documented above.
Standard setup checklist for new Vapi → GHL inbound client
- Create GHL Inbound Webhook workflow → copy webhook URL
- Patch Vapi assistant
serverMessagesto["end-of-call-report"]via API - Set Vapi assistant server URL to the GHL webhook URL
- Send sample payload to the GHL webhook URL
- In GHL workflow trigger → Mapping Reference → select the sample payload
- Build action steps using
inboundWebhookRequest.prefixed variables from the table above - Publish the workflow
- Make a real test call → confirm exactly 1 enrollment in Enrollment History
- Confirm all fields populated on the contact record
End-of-Day Update (2026-04-07)
Transcript Receiver — deployed to Cloudflare
The ghl-transcript-receiver Cloudflare Worker is now live:
- Worker:
https://ghl-transcript-receiver.johntossou.workers.dev - Webhook endpoint:
POST /webhook/transcript(no auth — GHL doesn't support request headers) - Query endpoint:
GET /transcripts?token=AUTH_TOKEN&date=YYYY-MM-DD - KV namespace ID:
01c5ffa00a554d96ab95ce889a97df6a - Wrangler config:
tools/cloudflare-workers/ghl-transcript-receiver.wrangler.jsonc - Auth token: stored in
.envasAUTH_TOKEN
Still required in GHL: go to Automation → "Transcript Generated" workflow → update the webhook action URL to the worker endpoint above → publish. Without this step, GHL won't push any transcripts to the worker.
GHL API — confirmed limitation
The GHL public REST API (/conversations/messages/{id}) does not return recording URLs or transcript text. These are stored GHL-internally. The only programmatic path is the "Transcript Generated" webhook workflow.
Twilio also does not hold the recordings from GHL native dialer calls — GHL uses its own pipeline.
GHL call recording — Camille's number
Call recording is not enabled on +44 7414 269881. Camille's human calls connect and last up to 5 minutes but leave no transcript. Enable recording in GHL → Phone Numbers → +44 7414 269881 → Call Recording ON.
2026-04-07 AI calling session findings
20 VAPI calls across 2 batches (~$0.73). Key issues observed:
- Premature hang-up — AI said "Goodbye" while a receptionist was mid-sentence giving an email address (London City Skin Clinic). Bhavisha prompt needs a longer patience window before ending when a human is actively speaking.
- Garbled primary_issue — Halcyon Medispa had a broken observation ("positive reviews costing inquiries"). Field content must be validated before calls go out.
- Best near-miss — Gielly Green: AI disclosed itself, Christie fetched the owner, call timed out on hold. Silence timeout threshold may need extending when AI has been explicitly told to hold.
End-of-Day Update (2026-04-04)
By the end of the 4 April 2026 session, the main shift was this:
- Vapi prompting and GHL enrichment are no longer the only concern
- the next automation layer is now a post-call renderer for email follow-up
New operating principle
Do not let GoHighLevel send post-call follow-up emails by stitching together raw dropdown values.
Use this pattern instead:
- GHL workflow is triggered by a custom disposition
- GHL waits ~10 minutes for transcript / summary availability
- GHL calls an external renderer endpoint
- the renderer combines:
- transcript nuance
- canonical GHL fields
- disposition
- the renderer writes final copy back into GHL
- GHL only sends if
render_status = ready
Why this matters
The live outbound schema uses machine-friendly fields like:
- primary_issue
- booking_system
- team_structure
Those are excellent for:
- filtering
- routing
- choosing the angle
They are not finished copy.
That means:
- primary_issue should not be pasted raw into an email
- GHL template logic alone is too brittle for high-quality personalised follow-up
Local build status
Prepared locally:
docs/aurea-post-call-renderer-design.mddocs/ghl-post-call-renderer-workflow-blueprint.mdtools/cloudflare-workers/aurea-followup-renderer.jstools/cloudflare-workers/aurea-followup-renderer.wrangler.jsonctools/cloudflare-workers/README-aurea-followup-renderer.mdtools/setup_ghl_render_fields.py
Not yet live
Two blockers remain:
- Cloudflare deploy
-
wrangleris not authenticated on this machine yet -
GHL render-field creation
- the current GHL token can read and update contacts
- but it does not have the scope to manage custom field definitions
- so the renderer fields still need manual creation or a higher-scope token
Required renderer fields
rendered_email_subjectrendered_email_bodyrender_statusrender_typerender_confidencerender_error
Best-practice conclusion
For Aurea’s post-call follow-up layer, the safest stack is now:
- Vapi handles the call
- GHL owns workflows and sending
- Cloudflare renders bounded copy
- tasks happen only on exception branches
Update suite au feedback de Claude
One important refinement was added after architecture review:
- the renderer should not become a fragile all-or-nothing dependency
So the recommended v1 is now:
- fallback-first
- renderer second
In practice that means:
- safe fallback templates should exist before renderer rollout
- transcript quality should be checked before transcript-based rendering
- if rendering fails, times out, or lacks enough context, the system should degrade gracefully rather than silently skip follow-up
- the renderer remains a quality layer, not the only path to a follow-up email
Update Note (2026-04-04)
This document began as a Vapi + GHL integration reference, but it now also needs to reflect the live demo-clinic voice setup.
Important live clarifications:
+44 1355 209592is the Demo Voice number, not the default Bhavisha prospecting number- the inbound demo assistant on that number is
Riley - Riley assistant ID:
cca2a23d-abcf-45ed-9aca-f54902ae3aaf - Riley is a demo clinic front-desk / after-hours reception assistant only
- Riley should remain separate from Bhavisha outbound and callback roles
Voice configuration clarification:
- the exact ElevenLabs voice ID for Bhavisha 2 is
BIS6xSao7QaZrZ0MgsWG - if Riley uses the Bhavisha 2 voice for demo consistency, document that explicitly rather than inferring it from another assistant
Prompting clarification:
- for demo inbound agents, pronunciation and pacing should not rely only on prompt wording
- use Vapi voice-layer formatting / replacements and Deepgram keyterms where possible
- keep the prompt structured into sections and keep it to one question at a time
Outbound schema clarification:
- the live JCT Advisory outbound schema is now locked to:
decision_makerbooking_systemprimary_issuemeta_adsgoogle_adsteam_structureworth_mentioning- these are now the source-of-truth fields for Bhavisha personalization
- the older
vapi_observation / vapi_leak / vapi_anglemodel is now historical, not canonical
Executive Summary
We now have two useful patterns for connecting Vapi and GoHighLevel:
-
Transcript push workflow
This sends transcript-related data out of GoHighLevel to our own webhook endpoint. -
External call logging workflow
This accepts a webhook into GoHighLevel and creates a contact + logs an external call directly into the contact's native activity / call history.
The important result from testing on JCT Advisory is:
- the
Inbound Webhook -> Create Contact -> Log External Callworkflow executes successfully - it creates the contact
- it adds an outbound call activity in GoHighLevel
- this means we likely do not need the full Marketplace / Conversation Provider route for this use case
That is a meaningful simplification.
What We Confirmed
1. The native GHL workflow path works
We tested this workflow:
Inbound Webhook -> Create Contact -> Log External Call
Using a test payload, GoHighLevel:
- accepted the webhook
- created the contact
John Test - logged an Outbound Call
- showed the result on the contact record
This is the most important practical finding.
2. The workflow must use webhook payload variables, not contact variables
When using Inbound Webhook, the early workflow steps do not yet have a GHL contact object.
So for Create Contact, you must map fields from the incoming webhook payload, for example:
phonefirstNamelastName
Do not map fields like:
{{contact.first_name}}{{contact.last_name}}{{contact.phone}}
Those are empty before the contact exists, and the step fails.
3. Log External Call is strict about values
For the external call step:
directionshould be lower-case:inboundoroutboundstatusshould use allowed values such as:completedansweredbusyno-answerfailedcanceledvoicemailpending
4. You can leave the date blank
If the Date field is left blank in Log External Call, GoHighLevel will apply the current date and time automatically.
That is useful for fast testing.
5. Use the real outbound number in From
For accurate logging, the From field should be the real caller number used by the Vapi outbound setup.
For the Bhavisha / JCT Advisory setup, the Vapi outbound number must match the live prospecting architecture.
Important clarification:
+44 1355 209592is now the demo inbound number used by Riley- do not treat
+44 1355 209592as the default Bhavisha outbound number unless the live routing has explicitly been changed again - always cross-check the current source of truth in
docs/phone-number-architecture.md
At the time of the original test, the number we resolved was:
+441355209592
6. The public workflow creation API is not available in the way we hoped
We tested the public GHL API and found:
GET /workflows/returned an authorization / scope issuePOST /workflows/returned404 Not Found
So, at least with the current token and public API surface, we should assume:
- workflows need to be created in the GHL UI
- then tested via webhook
We should not assume we can fully automate workflow creation programmatically.
Workflow 1: Transcript Workflow
What it does
This workflow sends transcript-related call data out of GoHighLevel to our own webhook.
In the current setup:
- trigger:
Transcript Generated - action:
Webhook - destination: our ngrok / server endpoint
What data it sends
Based on the current workflow, it sends values such as:
contactIdcontactNamephonecompanyNametranscriptsummarycallDurationdirection
What this workflow is for
This workflow is useful when:
- GoHighLevel already has the call / transcript event
- we want to push the transcript elsewhere
- we want custom downstream processing
- we want to enrich, summarize, store, or route the transcript outside GHL
In simple terms
GoHighLevel says:
"A transcript has been generated. I will now send that data to your server."
So this workflow is:
GHL -> our webhook
Best use case
Use this when the transcript already exists inside GHL and you want custom handling outside GHL.
Workflow 2: Vapi External Call Logging Workflow
What it does
This workflow lets an external system send call details into GoHighLevel.
In the tested setup:
- trigger:
Inbound Webhook - action 1:
Create Contact - action 2:
Log External Call
What this workflow is for
This workflow is useful when:
- Vapi handles the call
- we want GHL to reflect that call natively
- we want a call activity in the contact record
- we want to avoid a more complex Marketplace / Conversation Provider setup
In simple terms
Vapi (or our script) says:
"Here is a call that happened. Please create or update the contact, then log the call in GHL."
So this workflow is:
Vapi / script -> GHL webhook
What we tested successfully
We sent this style of payload:
{
"phone": "+447000000001",
"firstName": "John",
"lastName": "Test",
"direction": "outbound",
"status": "completed",
"duration": 125,
"recordingUrl": "https://example.com/test-recording.mp3"
}
And GHL successfully:
- created the contact
- logged the call
- showed the call activity on the contact
Best use case
Use this when Vapi is the voice runtime and GHL should reflect the call outcome inside the CRM.
Recommended Architecture Going Forward
Best default approach for Vapi outbound / external calls
For real Vapi call logging into GHL, the cleanest current direction is:
- Vapi finishes the call
- Vapi or our bridge sends a webhook to GHL
- GHL workflow creates / updates the contact
- GHL logs the external call natively
This gives us:
- simpler architecture
- less Marketplace complexity
- reduced developer billing risk
- cleaner CRM visibility
What to keep as fallback
We should still keep the Python bridge available as fallback:
tools/vapi_to_ghl_bridge.py
Why:
- the new workflow path is now validated for basic call logging
- but the bridge is still useful for:
- richer transcript storage
- custom notes
- custom business logic
- backup if GHL workflow behavior changes
So the bridge should not be deleted yet.
Next Step: Structured Clinic Context For Bhavisha
The bigger goal is not just call logging.
The real system goal is:
- store structured observations about each clinic inside GoHighLevel
- pass those fields into the Vapi agent
- make each Bhavisha call feel like a short spoken diagnostic audit
- test whether better context increases conversion rates for cold outreach
This is now the recommended next build step.
Design rules
These are the rules we want to keep:
- max 8 fields
- each field has exactly one job
- each field must be speakable in under 10 words
- if a field is empty, Bhavisha ignores it completely
- every field must be fillable by a human researcher or an AI scraper in under 5 minutes per clinic
These rules are important because they force the context to stay usable in real calls.
Proposed field schema
This section is now historical.
Use it only to understand the older Vapi-first model.
As of 2026-04-04, the recommended canonical schema for JCT Advisory outbound prep is the newer GHL contact schema documented in:
- vapi-outbound-routing-system.md
- jct-ghl-vapi-alignment-audit-2026-04-04.md
Deprecated as source-of-truth fields:
- vapi_observation
- vapi_leak
- vapi_angle
The current recommended schema is:
| GHL Field Name | Vapi Variable | Purpose | Example |
|---|---|---|---|
decision_maker |
{{decisionMaker}} |
Best person to ask for by name | Sarah Johnson |
booking_system |
{{bookingSystem}} |
What booking system they use | Phorest |
primary_issue |
{{primaryIssue}} |
The single sharpest diagnostic angle | no_online_booking |
meta_ads |
{{metaAds}} |
Observable Meta ads state | Past ads, pixel on site |
google_ads |
{{googleAds}} |
Observable Google Ads state | Active |
team_structure |
{{structure}} |
Solo vs team context | Team |
worth_mentioning |
{{notes}} |
Nuance or second-order detail | Google reviews mention slow callbacks |
Important note:
- if
clinic_typealready exists in GHL, treat it as an existing reusable field, not a brand-new one - if
firstNameor contact name already covers the decision-maker use case well enough,decision_makercan be reconsidered later
Live field lock for the current JCT Advisory build:
- decision_maker
- booking_system
- primary_issue
- meta_ads
- google_ads
- team_structure
- worth_mentioning
Do not rename these without updating:
- the GHL enrichment and push scripts
- the Vapi personalization mappers
- the Bhavisha prompt docs
How Bhavisha should use the fields
The purpose is not to dump all the data into the script.
The purpose is to make the call feel informed, precise, and calm.
Current recommended usage logic:
- If
{{decisionMaker}}is present, Bhavisha can ask for the person by name. - If
{{bookingSystem}}is present, Bhavisha can anchor the observation in that system or flow. - If
{{primaryIssue}}is present, Bhavisha should frame the conversation around that one issue rather than stacking multiple claims. - If
{{metaAds}}or{{googleAds}}are present and relevant, Bhavisha may use them as supporting context, not as the main opener. - If
{{notes}}is present, Bhavisha should use it sparingly and only if it helps credibility. - If a field is empty, Bhavisha should ignore it completely.
- Bhavisha should never say she "researched" the clinic. The specificity should do the work.
Prompt behavior rules
These are the operating rules the prompt should follow:
- use at most one strong detail early
- do not stack
observationandproofPointin the opening - if
observationexists, prefer it as the first specific detail - if the call is going well, keep the detail light and diagnostic
- if the person pushes back,
proofPointcan be used once as grounding - if
toneHintsaysbusy owner-operated, be shorter and softer - if
toneHintsayspremium, slow-burn, avoid sounding transactional - if
angleexists, keep the conversation focused around that single problem frame
How the fields get populated
There are two valid paths.
Path A: Manual now
Camille or another researcher fills 3-4 fields per clinic before calling:
vapi_observationvapi_leakvapi_anglevapi_tone_hint
This should take about 3 minutes per clinic.
This is the right immediate operational path.
Path B: Automated later
A clinic intelligence scraper fills the full schema from:
- website
- Google Business Profile / reviews
- social links
- booking path
That would reduce the manual prep work later.
What we should build next
The immediate next implementation should be:
- create the custom fields in GHL
- update
vapi_place_personalized_call.pyto pull those fields from GHL - map them into Bhavisha's Vapi variable values
- update the prompt so it uses the variables conditionally and lightly
- test on a small batch of clinics
What success looks like
A good version of this system should produce calls that:
- sound specific without sounding creepy
- feel like a short spoken audit, not a generic sales pitch
- stay consistent across many clinics
- can be improved by refining field quality rather than rewriting the whole agent
Practical implementation order
Recommended build order:
- Keep call logging working first
- Add the field schema in GHL
- Add field extraction to
vapi_place_personalized_call.py - Update Bhavisha prompt rules
- Run 10-20 test calls with structured clinic context
- Compare results against generic calling
This is the right way to test the real hypothesis:
does precise diagnostic context, delivered consistently at scale, improve cold-call conversion with clinics?
Practical Best Practices
1. Keep the webhook payload simple
Start with the smallest useful payload:
- phone
- firstName
- lastName
- direction
- status
- duration
- recordingUrl
Do not overcomplicate the first version.
2. Test with fake data first
Before using real Vapi traffic:
- send a simple webhook manually
- confirm contact creation
- confirm call logging
- confirm the activity looks correct in GHL
This saves a lot of time.
3. Publish before testing
Draft workflows may look configured but still not behave as expected.
Always:
- save
- publish
- then test
4. Check Execution Logs before checking the contact
The fastest debugging order is:
- Did the webhook trigger?
- Did
Create Contactexecute? - Did
Log External Callexecute? - Then inspect the contact record
5. Do not assume a field is mapped correctly just because it “looks filled”
In GoHighLevel, a field can look populated but still point to the wrong data source.
Always ask:
- is this a value from the webhook payload?
- or is it a value from the contact object?
That distinction matters a lot.
6. Use the real outbound number in From
If the goal is to reflect the real call source, use the real Vapi outbound number in From.
Important architecture warning:
+44 1355 209592is currently the demo voice number for Riley- do not blindly reuse older documentation references for Bhavisha call logging
- confirm the live prospecting number before treating any
Fromvalue as authoritative
For Bhavisha / JCT Advisory, the older documented number was:
+441355209592
7. Use lower-case call values
Safer defaults:
direction:inbound/outboundstatus:completed,answered, etc.
Avoid guessing capitalization.
8. Treat workflow UI setup as part of the real system
Even if the API is limited, the workflow UI can still be a robust production tool.
Do not over-prioritize API purity if the UI gives a simpler and more reliable path.
When To Use Which Workflow
Use the Transcript Workflow when:
- GHL already has the transcript event
- you want to send transcript data out to your own server
- you want custom processing outside GHL
Use the External Call Logging Workflow when:
- Vapi is handling the call
- you want the call reflected directly in GHL
- you want native CRM call visibility
- you want to avoid Marketplace / Conversation Provider complexity
Current Recommended Decision
For Vapi + GoHighLevel call logging, the current best practical recommendation is:
- use GHL Inbound Webhook + Create Contact + Log External Call for native CRM call logging
- keep the Python bridge as a fallback / enrichment layer
- do not assume Marketplace / Conversation Provider is necessary unless a later requirement forces it
Demo Inbound Assistant Best Practices (Aurea Demo Clinic)
This section is specifically for the demo clinic inbound experience, not the outbound Bhavisha system.
Live role
- assistant name:
Riley - assistant ID:
cca2a23d-abcf-45ed-9aca-f54902ae3aaf - number:
+44 1355 209592 - purpose: after-hours clinic reception demo
Design rules
- keep this assistant separate from all outbound prospecting roles
- it should sound like a premium clinic front desk, not a sales bot
- it should handle inbound enquiries, basic screening, booking next steps, and message-taking
- it should not give medical advice
- it should not directly manage existing appointments beyond taking a callback message
Prompt rules that proved useful
- separate the Vapi
firstMessagefrom the main system prompt - structure the prompt into sections: identity, scope, flow, routing, hard rules
- ask one question at a time
- keep replies short enough to sound spoken rather than read
- write for natural British phone speech, not for chatbot-style completeness
- avoid rigid exact-line scripting unless legally necessary
Pronunciation and speech handling
For demo assistants, pronunciation should be handled in layers:
- prompt clarity
- Vapi voice-layer replacements / formatting
- transcriber keyterms for brand and treatment names
Current examples worth preserving:
Aureapronunciation supportProfhilopronunciation supportpolynucleotidespronunciation support- Deepgram keyterms for clinic-specific and treatment-specific phrases
Voice configuration
The exact ElevenLabs voice ID for Bhavisha 2 is:
BIS6xSao7QaZrZ0MgsWG
If this voice is reused on demo agents like Riley, document it explicitly in the assistant notes and architecture docs so the live setup stays traceable.
Stress-test scenarios the demo assistant must handle cleanly
- new treatment enquiry
- existing appointment / reschedule request
- price question
- urgent concern / reaction concern
- request to speak to the practitioner directly
- caller says they never received the booking link
- silent caller
- wrong number / out-of-scope caller
Next Build Concept: AI Reveal System (2026-03-31)
The idea
Two call cases that turn the AI nature of the system into the product demo itself.
Case 1 — Outbound cold call
Bhavisha opens with one sharp, personalised observation about the clinic before any pitch. The observation is pulled from GHL fields (vapi_observation, vapi_leak). Once the person engages, Bhavisha reveals she is an AI. The reveal is not a confession — it is proof of concept delivered live. The call becomes a demo, not a sales conversation.
Suggested opening:
"Hi, is that [NAME]? I noticed your booking link goes to a contact form rather than a calendar — I'd guess that loses you a few enquiries a week. I'm actually an AI calling on behalf of Aurea Growth — which is the point. Worth a quick chat to see if something like this makes sense for your clinic?"
Case 2 — Missed call callback (inbound)
When a clinic owner calls back the outbound number after a missed call, the AI answers:
"Hi, is that [NAME]? Thanks for calling back. I'm essentially calling to solve the exact problem you're facing right now — catching up with leads you missed while you were busy."
The irony does the selling. They just lived the problem in the last 60 seconds.
Why Case 2 is particularly strong
The clinic owner calls back an unknown number, an AI picks up, and the opening line names the exact problem they just experienced. The product sells itself before any pitch is made. There is no equivalent moment in standard cold outreach.
Design rules for the reveal
- The reveal must happen after the observation lands and the person engages, not on a timer and not immediately.
- Trigger: they respond positively or ask a follow-up question — then Bhavisha says it.
- Too early: they hang up. Too late: it feels like a trick.
- The reveal line should be short and confident, not apologetic.
What needs to be built
| What | Change needed |
|---|---|
| Bhavisha prompt (Case 1) | Add reveal logic: after engagement signal, reveal AI identity as capability proof |
| Case 2 agent | Separate Vapi assistant — inbound handler, different opening, different script |
| GHL workflow | Route missed-call-callbacks to the Case 2 agent's phone number |
vapi_leak field |
Already exists — move it into the opening line, not buried later |
What already exists
- GHL custom fields (
vapi_observation,vapi_leak,vapi_angle,vapi_tone_hint) are designed for exactly this — feeding the personalised opening vapi_place_personalized_call.pyand the batch caller already inject these into Vapi variable values- The GHL call logging workflow already handles outcomes
The reveal logic and Case 2 agent are the only new pieces needed.
Build Status: AI Reveal System (updated 2026-04-04)
What has been written
| File | What it is | Status |
|---|---|---|
tools/vapi_cold_prompt_v2.txt |
Case 1 — outbound cold call with AI reveal | Live in Vapi, updated 2026-04-04 |
tools/vapi_callback_prompt.txt |
Case 2 — inbound callback handler | Live in Vapi, updated 2026-04-04 |
tools/vapi_batch_caller.py |
Batch caller CLI | Live |
tools/vapi_caller_ui.py |
Browser UI for batch calling | Live |
tools/vapi_place_personalized_call.py |
Single call with GHL context | Live |
tools/push_cold_prospects_to_ghl.py |
Scrape → score → push to GHL | Live |
What still needs to be built
Step 1 — Create GHL custom fields
- Create these custom contact fields in GHL (Settings → Custom Fields):
- vapi_observation
- vapi_leak
- vapi_angle
- vapi_tone_hint
- These are what gets filled per clinic before calling
Step 2 — Update vapi_place_personalized_call.py to pull custom fields
- Currently only pulls core contact fields (firstName, companyName, tags)
- Needs to also read the 4 custom fields from GHL and pass them into Vapi variable values
Step 3 — Maintain live Vapi assistants
- Case 1 prompt is already live in Vapi
- Case 2 assistant is already created and live in Vapi
- keep assistant IDs documented when changing prompts or settings
- keep the shared voice ID documented: BIS6xSao7QaZrZ0MgsWG
Step 4 — GHL workflow for inbound callbacks / forwarding
- Create a GHL workflow: Inbound Call → (if contact tagged outbound-call-completed) → route to Case 2 Vapi assistant
- GHL needs to forward the inbound call to the Case 2 Vapi number
- Alternatively: configure the Vapi phone number directly as the inbound handler
- Current status: still blocked / unresolved with GoHighLevel as of 2026-04-04
Step 5 — Test the full loop
- Push 5 cold prospects via push_cold_prospects_to_ghl.py
- Fill vapi_observation and vapi_leak on each manually
- Run batch caller via the UI
- Confirm GHL logs the outcomes and applies tags
- Call back the outbound number from a test phone
- Confirm Case 2 agent answers with the callback opening
- Confirm both assistants can check live availability and create a real appointment on calendar K5k7NPpz9lKadHgt7V5x
Full loop (when all steps are complete)
push_cold_prospects_to_ghl.py
→ 30 ICP-matched clinics pushed to GHL with tags + angle notes
↓
Enrich each contact in GHL (vapi_observation, vapi_leak, vapi_angle, vapi_tone_hint)
↓
Aurea Caller UI → Start Calling
→ Bhavisha calls each clinic (Case 1 prompt)
→ Opens with sharp observation, reveals AI after engagement
→ GHL logs outcome, applies tags (voicemail / no-answer / completed / callback-requested)
↓
Clinic owner calls back the outbound number
→ Case 2 agent picks up
→ "I'm solving the exact problem you're experiencing right now"
→ Books discovery call
Live state now
- Bhavisha Case 1 assistant is live
- Bhavisha Case 2 assistant is live
- both assistants now use the Bhavisha 2 ElevenLabs voice
- both assistants were updated on 2026-04-04 with improved settings and prompt behavior
- both assistants now have GoHighLevel tools attached in Vapi for contact lookup / creation, calendar availability, and calendar event creation
- both assistants are now instructed to book directly into
Aurea Growth | Intro Call(K5k7NPpz9lKadHgt7V5x) when the prospect agrees to a meeting - the forwarding problem in GoHighLevel is still unresolved and remains under discussion with GHL
Known Open Questions
These are still worth verifying later:
- whether all real Vapi call outcomes map cleanly into GHL status values
- how best to handle inbound vs outbound in production payloads
- whether recording URLs always display the way we want in GHL
- whether transcript content should still be stored separately as notes or pushed elsewhere
- whether long-term production load introduces any workflow edge cases
Short Version
If someone asks, “What did we learn?” the short answer is:
We proved that Vapi call data can be pushed into GoHighLevel using a simple inbound webhook workflow. GHL can create the contact and log the call natively, which means we likely do not need the Marketplace / Conversation Provider route for this use case. The old transcript push and Python bridge still matter, but the simpler native workflow is now the preferred first option for call logging.
Related Notes
Autogenerated navigation links to improve Obsidian connectivity.
- [[docs/vapi-outbound-routing-system|Aurea AI Outbound Routing System]]
- [[docs/jct-ghl-vapi-alignment-audit-2026-04-04|JCT Advisory GHL ↔ Vapi Alignment Audit]]
- [[docs/ghl-post-call-renderer-workflow-blueprint|GHL Post-Call Renderer Workflow Blueprint]]
- [[docs/aurea-post-call-renderer-design|Aurea Post-Call Renderer Design]]
- [[docs/aurea-gtm|Aurea Growth — Go-to-Market Strategy]]
- [[aurea-growth-encyclopedia/wiki/index|Aurea Growth Encyclopedia]]
Activation Prompt
You are in AI Websites mode. Read docs/Doc Business/ai-website-agency-sales-playbook.md and workflows/us-trades-website-pivot-workflow.md before planning, selling, or building anything. Live state (June 2026): active market is US trades (roofers, plumbers, HVAC, landscapers, electricians, builders). Caller: Aubrey (GHL + Jibble). Demo format: phone-first — John calls the prospect; they open the Cloudflare-hosted mockup on their phone. No Google Meet by default. Offer: $750 setup + $297/month. Do not build a full custom site before payment; use fast source-mapped mockups only. Never invent proof, licenses, reviews, or credentials. Keep trades and clinics as separate sales motions.
US Trades Website Pivot: Master Workflow
Status: Active
Last updated: 2026-06-22
Owner: John Tossou
Ops lead: Camille Arcillas
Callers: Aubrey (active), Blessy (pending confirmation)
This is the single source of truth for the US trades cold calling and website mockup workflow. All previous versions in emails and threads are superseded by this document. Update this file whenever a process change is agreed.
1. Objective
Call US trades business owners (plumbers, roofers, landscapers, electricians, builders, HVAC), show them a personalised website mockup built from their real reviews and services, and close a recurring website + local enquiry system deal by phone.
Core offer: $750 setup + $297/month (website, hosting, maintenance, local SEO basics, enquiry capture, missed-call follow-up).
2. Team and Roles
| Person | Role | Scope |
|---|---|---|
| John | Pipeline review + escalation | Weekly pipeline review, available for objections Aubrey cannot handle. Not required for individual deals to close. |
| Camille | Ops lead + Closer | GHL backend, caller management, mockup builds, teaser sends, demo callbacks + verbal close, Stripe link sending, KPI tracking, weekly payment sync |
| Aubrey | Caller only | Cold calls US trades from GHL, sets dispositions, captures emails, books callback tasks for Camille. No demo callbacks. |
| Blessy | Caller (DECLINED 2026-06-16) | Withdrew due to increased hours and house move. Never made a call. |
Role change 2026-06-23: Aubrey stepped back from closing callbacks (WhatsApp, 15:36). Reason: not yet confident enough to handle detailed questions about how the mockups are built. She asked for Camille to take the closing calls while she focuses on volume and cold calling. John approved. Camille is now the primary closer. Aubrey and Camille discussed scheduling around EST timezone coverage.
Caller accountability (Camille): Review dispositions daily. Track hours via Jibble. Send a daily report to John every evening plus a full weekly summary before the Friday payment call.
Aubrey daily report format (Camille sends every evening):
Aubrey daily report
Hours worked:
Calls made:
Connects:
Emails confirmed:
Mockups requested:
Phone calls booked:
No-shows / reschedules:
Issues:
3. Tech Stack
| Tool | Purpose |
|---|---|
| GHL (GoHighLevel) | CRM, pipeline, dispositions, workflows, outbound calling |
| Jibble | Time tracking for callers |
Drive folder 1584caDtAZsY9pjeqnhyHhvo5-EisTGzW |
Mockup templates, README, Claude Code skill prompts |
| Claude Code | Mockup generation (HTML) + deploy script (tools/deploy_mockup.py) |
| Cloudflare Pages | Hosts live mockup links — project: aurea-mockups. Deploy command: python3 tools/deploy_mockup.py "client-demos/<name>/dist" --business "Name" --city "City" |
| Stripe | Payment collection. Auto-debit from Day 1. No work starts before first payment. |
| WhatsApp (Camille-managed groups) | Daily check-ins with callers — separate group per caller |
SMS / A2P note: SMS delivery to prospects is not active yet. A2P certification is in progress in parallel. For now, all teaser and confirmation messages go by email only.
Cloudflare deploy: tools/deploy_mockup.py deploys a finished dist/ folder to Cloudflare Pages (aurea-mockups project) and returns a live URL. Camille uses this URL in the teaser email and GHL. See docs/Camille/deploy-mockup-sop.md for the full guide.
4. Lead Discovery (Weekly — John or Camille)
Source: tools/discover_us_trades_leads.py + tools/push_us_trades_prospects_to_ghl.py
Target volume: ~1,000 contacts per week (enough for a full day of calling per caller).
Each contact pushed to GHL gets:
- Tags: us-trades, website-pivot, state tag (e.g. fl), website status tag, caller tag
- Pre-populated fields: business name, phone, current website URL, review count, suggested_script_line
Website status tags:
- no-website — no web presence found
- weak-website — basic template, poor conversion, low trust signals
- existing-website — decent site, angle shifts to improvement and missed-call capture
Filtering criteria (minimum bar): 15+ Google reviews, 4.5+ rating, verified phone number. Lower volume is fine if quality is higher.
5. The Caller Script
Aubrey reads the pre-written line from the suggested_script_line field in GHL. She does not rewrite or interpret it.
Script by website status:
No website:
"You've got [X] Google reviews but I couldn't find a proper website. I put together an example using your real reviews and services. Takes 10 minutes to show you — worth a look?"
Weak website:
"You've got [X] Google reviews but your site looks like a basic template. I put together a cleaner example using your real reviews and services. Takes 10 minutes to show you — worth a look?"
Existing website:
"You've got [X] Google reviews and a website already. I put together a stronger version using your real reviews and services, focused on turning more Google searches into calls. Takes 10 minutes to show you — worth a look?"
When they say yes — booking line (use exactly):
"We'll send it to your email now. I'll call you back after you've had a look. What's a good time today?"
Get the email on the call. Read it back to confirm. Set a GHL callback task at the agreed time. Aubrey calls them back herself.
No Google Meet. No John calendar. Aubrey owns the callback.
When they say "just send me an email":
1. Aubrey asks for their email on the call and reads it back to confirm
2. After the call, goes into GHL, adds the email, applies the mockup-requested tag, leaves a one-line note
3. The mockup-requested GHL workflow fires and alerts Camille to build the mockup and send it directly
6. GHL Dispositions
After every call, Aubrey selects exactly one disposition. The corresponding workflow runs automatically.
| Disposition | What happened | Workflow triggered |
|---|---|---|
appointment_booked |
Prospect agreed to a phone demo | WF1: Demo Booked |
callback_scheduled |
Prospect asked to call back at a set time | WF callback sequence |
callback_no_response |
Prospect missed all Aubrey callback attempts | Final missed-callback email, then move out of active callback queue |
info_sent (mockup-requested) |
Prospect asked for an email | Mockup-requested internal alert |
not_interested |
Clear no | WF5: Not Interested |
incorrect_number |
Wrong or dead number | WF4: Incorrect Number |
no_answer |
No pick-up, max attempts reached | WF2: No Answer |
7. GHL Workflows
WF1 — Demo Booked (triggers on appointment_booked tag)
- Add
demo-bookedtag - Move opportunity to Booked Stage
- Create internal task: "Website Mockup + Teaser Email — [Business Name]" — assigned to Camille, due same day
- Send internal alert email to john@aureagrowth.co AND camille@aureagrowth.co with all of:
- Prospect first name and full name
- Business name and city/state
- Current website URL
- Mobile number called
- Call type (phone — default from here)
- Scheduled date, time, and timezone
- Website status tag
- Review count and business category
- Suggested angle line from
suggested_script_line - Fire calendar invite to prospect immediately (before confirmation email)
- Once Camille completes the mockup: send combined confirmation + teaser email to prospect
WF1A — No Show (triggers when prospect misses booked demo)
Sends a follow-up email with calendar link to reschedule easily.
WF2 — No Answer
Sends short email introducing the website example with a CTA to book directly.
WF3 — Send Info / Mockup Requested
Internal alert to john@ and camille@ with business name, website, email, and Aubrey's note. Creates GHL task assigned to Camille: "Build mockup: [Business Name]" due same day.
Once Camille sends the mockup link, the same existing alert/context should also be sent to Aubrey before her callback. John stays copied for visibility.
WF3A — Missed Camille Callback / No Response
This is separate from WF1A. WF1A is for formal booked demos. WF3A is only for Camille's mockup callbacks.
If prospect misses the agreed callback:
1. Attempt 1: Camille calls from GHL at the agreed time.
2. Attempt 2: if no answer, Camille tries again 45-60 minutes later the same day.
3. Attempt 3: if still no answer, Camille makes one final attempt on the next calling day.
4. If still no answer after attempt 3, Camille applies callback_no_response.
When callback_no_response is applied, GHL sends one short email:
Hi [First Name],
We tried calling you a couple of times to walk through the website we built for [Business Name].
Happy to find a better time — just reply here or call us back at [Number].
Thanks,
Aurea Growth
After that, move/archive the contact out of the active callback queue.
WF4 — Incorrect Number
Closes contact, keeps pipeline clean.
WF5 — Not Interested
Polite closing email, removes from active follow-up.
Important: GHL workflows are trigger-based and do not retroactively fire for contacts that existed before the workflow was updated. Any appointment booked before a workflow change will not receive new alert fields. Always test with a fresh test contact when adding fields.
8. Camille: Demo Prep Checklist
When the WF1 alert arrives, complete before the demo time:
- Check current website: weak, decent, or none?
- Check Google Business Profile: review count, category, photos available
- Check for existing automation: chat widget, booking tool, contact forms, GHL signs
- Choose the best angle:
- Weak/no site: "cleaner, mobile-first, turns searches into calls"
- Existing decent site: "stronger version with missed-call capture, review proof, direct enquiry"
- Has GHL already: pivot to SEO/local visibility angle, do not sell automation they already have
- Pick the best matching template from the Drive folder
- Build mockup HTML using Claude Code and the skill prompts in the Drive folder
- Deploy to Cloudflare using the deploy script. From the workspace root:
python3 tools/deploy_mockup.py "client-demos/business-city/dist" --business "Name" --city "City"
The script validates the mockup, deploys toaurea-mockupson Cloudflare Pages, and outputs a live URL +teaser-email.txt. Full guide:docs/Camille/deploy-mockup-sop.md. - Send teaser email to prospect using the generated
teaser-email.txt— fill in[First Name]and[TIME], send from john@aureagrowth.co — email only (no SMS until A2P approved) - Log the send in GHL with tag
teaser_sent
Mockup templates and skill prompts: https://drive.google.com/drive/folders/1584caDtAZsY9pjeqnhyHhvo5-EisTGzW
9. Teaser Email Template
Subject: Your website example — [Business Name]
Body:
Hi [First Name],
Camille will call you at [time]. Here's the example we put together for [Business Name]: [link]
Open it on your phone before the call if you can. She'll walk you through it in 10 minutes.
Talk soon,
Aurea Growth
Send from john@aureagrowth.co or camille@aureagrowth.co. Signed as Aurea Growth.
[link] = Cloudflare live URL once the deploy script is ready. Until then = Drive share link with full folder (HTML + assets). Never share HTML-only.
10. John: Pre-Call Prep
When the WF1 alert arrives:
1. Read the alert fully: name, business, website, angle, call type, time
2. Open the mockup to know what you're showing
3. Have the live link ready to resend if needed
4. Note any existing automation — adjust angle accordingly
11. Camille: Demo Callback Script
Camille owns the full demo call as of 2026-06-23. Use the Aubrey Demo Call tab at call-script.johntossou.workers.dev (same script applies). John has scheduled a script review with Camille before she takes live calls.
Call opens:
"Hi [NAME], it's Camille from Aurea Growth — Aubrey mentioned she spoke with you earlier about your website. Did you get the email with the example? Open it on your phone and I'll walk you through it quickly."
Demo flow:
1. Restate their pain using exact words from GHL cold call notes.
2. Verbal site comparison: reviews buried on their current site vs. front and centre on the mock.
3. Walk through the mockup: hero, star rating + review count, services with Get a Quote, Text Us a Photo, missed-call follow-up.
4. Money math: "Even one extra job a month at [$X] covers the monthly cost twice over."
5. Offer: $3,500 anchor first, then $750 + $297/month as the logical choice.
6. Close: "Does this make sense for the business?" If yes: "I'll get our team to send you the payment link right now. What email should we use?"
After verbal yes:
- Apply verbal_yes tag in GHL
- Add note: "Agreed to $750 setup + $297/month. Email confirmed: [email]."
- WhatsApp Camille: "Verbal yes — [NAME] [BUSINESS] [EMAIL] — send Stripe now."
Both steps required. WhatsApp for speed, GHL for attribution.
Escalation:
If prospect asks detailed build/SEO/automation questions Aubrey cannot answer:
"Let me get John on a quick call to answer that properly — he handles the technical side."
Alert John by WhatsApp with name, business, and the specific question.
12. Post-Call (Camille)
Metric definitions:
- Demo Completed — Aubrey ran a real 3-5+ min demo callback and logged outcome in GHL
- Verbal Yes — prospect agreed verbally to $750 + $297/month
- Stripe Sent — Camille sent payment link
- Closed / Won — Stripe payment received and confirmed
| Outcome | Action |
|---|---|
| Demo Completed | Aubrey logs outcome in GHL. Camille audits daily. |
| Verbal Yes | Aubrey applies verbal_yes tag + note in GHL. WhatsApps Camille immediately. Camille sends Stripe link within 5 minutes and confirms back in group chat. |
| Closed / Won | Stripe payment confirmed. Camille creates client file, kicks off mockup-to-production handoff. |
| No-show | WF1A fires automatically. Aubrey rebooks if prospect is reachable. |
| Not interested after demo | Apply not_interested tag, archive contact. |
| Needs follow-up | Set GHL task with date and note. |
13. GHL Outbound Calling
John calls prospects from GHL using the US number. The default outbound number must be the US (+1) number, not the UK number.
Status as of 2026-06-18: Number selector identified and changed during the June 18 call. John confirmed it now shows the correct number. Camille to verify by running a test call and confirming caller ID. 3-line SOP to follow once confirmed.
Callback protocol: Aubrey books her own callback in GHL as a task at the specific time agreed on the cold call. No calendar link. No Google Meet. She calls the prospect back from GHL at that time using the US number.
14. Weekly Rhythm
| Day | Action |
|---|---|
| Weekly (Camille) | Push ~1,000 new leads to GHL |
| Daily (Aubrey) | Call from GHL, set dispositions |
| Daily (Camille) | Disposition review, mockup builds for any new bookings, WhatsApp check-in with callers |
| Friday (Camille) | Send caller summary report to John before payment call: hours, call volume, demos booked, issues |
| Friday (John + Camille) | Weekly sync call: pipeline review, caller performance, process changes |
15. Caller Compensation
Trial period: Hourly only at $5/hour via Jibble. No bonus during trial. Performance measured on: hours worked, call volume, dispositions set, notes quality, emails captured, demos booked, demos completed.
Weekly bonus (starting week of 2026-06-23) — based on Demo Completed, not booked:
| Demo Callbacks Completed | Weekly Bonus |
|---|---|
| 0–4 | $0 |
| 5–9 | $5 |
| 10–14 | $10 |
| 15+ | $20 |
Signed client bonus: $75 per Closed / Won where the first Stripe payment is received and the demo originated from Aubrey's callback. Does not count on verbal yes, pending invoice, or unpaid Stripe link. This is increased because Aubrey now owns both the callback and verbal close.
Definition of Demo Completed (5-point score, minimum 4/5):
- Right fit — US local trades business: plumber, roofer, landscaper, electrician, HVAC, builder.
- Decision-maker or real influence — owner, manager, or someone who can discuss the site.
- Clear interest — prospect genuinely engaged with the mockup. Not a vague "just send me info."
- Real conversation — Aubrey reaches the prospect at the agreed callback time and has a real 3-5+ minute demo conversation. If the prospect answers but is busy and reschedules, it stays pending.
- GHL clean — disposition set, notes written, phone and email confirmed, time logged, outcome recorded.
Booked vs Completed: Bonus applies on Completed only. Aubrey logs the outcome. Camille audits dispositions and notes daily and tracks the weekly total for payment. John does not need to confirm individual demos.
16. Pending Items (as of 2026-06-19)
| Item | Owner | Status |
|---|---|---|
| Audit WF1 alert fields, test with fresh contact, confirm both john@ and camille@ receive it | Camille | In progress (committed Jun 18) |
| GHL outbound calling: number changed on call, Camille to test and confirm caller ID, send 3-line SOP | Camille | Partially fixed — test pending |
| Update Aubrey's booking line (done in this workflow) — brief Aubrey on new wording | Camille | Done in workflow, brief Aubrey |
| Update GHL booking confirmation message (remove Meet link, add "Aubrey will call you") | Camille | In progress |
| Cloudflare deploy script: auto-push mockup HTML + assets, return live URL | John | In development (this week) |
| GHL custom fields cleanup: remove unnecessary fields to simplify Aubrey's view | Camille | In progress |
| Arturo (Ideal Gardens) + Express Soft: Aubrey to call back using new demo callback script | Aubrey | Pending (this week) |
| A2P SMS certification | John | In progress in parallel |
| Create combined Stripe checkout: $750 setup + $297/month subscription in one link | John | Pending — fallback is two-step ($750 first, subscription after) |
| Brief Aubrey on demo callback script and verbal-close process (GHL tag + WhatsApp Camille) | Camille | Pending |
| Decide whether Camille becomes backup/overflow callback closer after she discusses comfort and coverage with Aubrey | Camille + Aubrey + John | Open question — do not change default Aubrey-owned callback process yet |
| Update Camille daily report format to include: demo callbacks completed, verbal closes, Stripe payments confirmed | Camille | Pending |
| Confirm new bonus structure with Aubrey and add weekly bonus tracking to Camille's Friday caller summary | John + Camille | In progress |
17. Source Documents
| Document | Location | Notes |
|---|---|---|
| Mockup templates + README + skill prompts | Drive: 1584caDtAZsY9pjeqnhyHhvo5-EisTGzW |
Use for all mockup builds |
| Camille operating manual | Claude Code Workflow/CAMILLE.md |
Roles, calling windows, accountability rules |
| US trades prospecting pack | Claude Code Workflow/docs/Camille/us-trades-prospecting-pack.md |
Lead discovery scripts |
| Sales playbook | Claude Code Workflow/docs/Doc Business/ai-website-agency-sales-playbook.md |
Demo structure, pricing, close scripts |
| Website pivot transcript and plan | Claude Code Workflow/docs/Doc Business/website-pivot-ai-websites-transcript-and-plan.txt |
Locked strategy and sales motion |
18. Changelog
| Date | Change | Source |
|---|---|---|
| 2026-06-11 | John introduced mockup workflow to Camille. Drive folder and README shared. | "New workflow + weekly call updates" thread |
| 2026-06-12 | WhatsApp groups per caller agreed. Jibble tracking confirmed. Mockup-as-no-show-prevention locked. | Post-call recap email |
| 2026-06-15 | Camille built WF1-WF5 around custom dispositions. John requested internal mockup task in WF1. | "Workflow Setup Completed" thread |
| 2026-06-15 | Camille updated WF1 to include internal task + alert. Combined confirmation + teaser approach agreed. | Same thread |
| 2026-06-17 | Alert fields expanded: both john@ and camille@ must receive alert with all fields including call type. | John's email Jun 17 08:03 |
| 2026-06-17 | Mockup-requested workflow and Aubrey email-capture briefing added as requirements. | John's email Jun 17 08:08 |
| 2026-06-18 | Phone-first model locked. No Google Meet by default for trades. John calls from GHL US number. | "US trades workflow" master email |
| 2026-06-18 | Ideal Gardens alert root cause confirmed: appointment existed before workflow update. Not a broken workflow — a timing gap. | Camille's reply Jun 18 07:31 |
| 2026-06-18 | This document created as single source of truth. All previous versions superseded. | This document |
| 2026-06-18 | Cloudflare deploy script added to stack. Teaser delivery shifts from screenshot to live URL once script is ready. | June 18 call with Camille |
| 2026-06-18 | GHL outbound number changed to US during call. Pending test confirmation. | June 18 call with Camille |
| 2026-06-18 | Calendar protocol locked: Aubrey always uses calendar link, never manual booking. John blocked until Jun 22. | June 18 call with Camille |
| 2026-06-18 | Aubrey performance confirmed: good volume, confident, asks follow-up questions. Needs technical guidance on calendar. | June 18 call with Camille |
| 2026-06-18 | Elhama on hold: council flagged missing certification for one treatment, working with lawyer. | June 18 call with Camille |
| 2026-06-18 | Nurse Kelsey: final proposal sent, waiting. No further action needed. | June 18 call with Camille |
| 2026-06-19 | Blessy marked declined (withdrew 2026-06-16, never made a call). | CAMILLE.md |
| 2026-06-19 | Caller compensation structure documented. Weekly bonus ladder (starting week of Jun 23) and $30 signed-client bonus formalised. Qualified Demo Completed criteria locked. | This document |
| 2026-06-21 | Booking line updated: email-first approach locked ("What's the best email to send it to? John can give you a quick phone call after you've had a look."). Daily report format added for Camille. | June 18 call recap |
| 2026-06-22 | Aubrey promoted to Caller + Closer (interim). John removed from demo critical path. Aubrey runs full demo callback herself. Verbal yes triggers Camille to send Stripe within 5 min. GHL callback task replaces John calendar. Metric definitions separated: Demo Completed / Verbal Yes / Stripe Sent / Closed Won. | John decision |
| 2026-06-23 | Aubrey stepped back from closing (WhatsApp 15:36 — not confident handling mockup questions). Camille is now primary closer. Aubrey = cold calls only. Teaser email, demo script, and missed-callback sequence updated to reflect Camille as callback owner. John booked script review with Camille before live calls. | Aubrey WhatsApp |
| 2026-06-22 | Missed Aubrey callback sequence locked: agreed-time attempt, 45-60 min same-day retry, next-calling-day final attempt, then callback_no_response email and archive. Signed client bonus increased to $75 per paid client for Aubrey-owned callbacks. |
John decision |
| 2026-06-22 | Camille offered to help with some 10-minute callback/closing calls if timezone/availability makes that easier. Logged as open question only: Aubrey remains default callback owner; Camille may become backup/overflow after discussion with Aubrey. | WhatsApp audio |
AI Website Agency Sales Playbook
Reference playbook for building, selling, and scaling AI-assisted websites for local businesses.
Created: 2026-06-04
Primary sources:
- docs/Doc Business/website-pivot-ai-websites-transcript-and-plan.txt
- docs/Doc Business/500k - web AI.txt
- French transcript provided by John: "EUR400,000 per month with his incredible agency (copying his strategy)"
- docs/Doc Business/ai-one-person-business-playbook.md
- docs/Doc Business/jordan-unfair-ai-cold-outreach-reference.md
- docs/Doc Business/clinic-omnichannel-ai-stack-playbook.md
Important: this document is not a promise that the model will hit the same numbers as the agencies in the videos. It is a practical operating reference for Aurea Growth to test the model with lower complexity, faster delivery, and better cash discipline.
Locked strategy update:
This is not a pivot into a generic web agency. Aurea is testing a local enquiry system for high-ticket local businesses. The website is the wedge. The recurring value is visibility, trust, enquiry capture, reviews, follow-up, and maintenance. AI is used internally first and sold as an upsell only after trust is built.
Locked operating nuance:
- Keep trades and clinics as separate sales motions. Trades are owner-led, phone-first, and usually do not have gatekeepers. Clinics are more likely to have receptionists, office managers, booking platforms, and compliance concerns.
- Do not use a single Google review threshold across niches. For UK plumbers, roofers, and driveway installers, 15-30 reviews with a 4.5+ rating can be a strong demand signal. For premium clinics, dentists, and private healthcare, 50-100+ reviews is the stronger bar.
- The mockup rule is not "finish it in 8 minutes." The rule is: no full custom build before payment. A useful personalised mockup screenshot can take 20-30 minutes if the prospect is worth it.
- Camille owns daily caller accountability: disposition review, KPI tracking, script QA, and escalation to John when the caller drifts or underperforms.
- On demo calls, assume forward motion once value is clear. Do not ask a soft permission close that invites hesitation.
Live operating state (as of June 2026):
- Active market: US trades — Florida roofers first, expanding to plumbers, electricians, landscapers, HVAC, builders
- Caller: Aubrey (active). Blessy declined (June 16, never made a call).
- Demo format: phone-first, not Google Meet. John calls the prospect at the booked time. The prospect opens the Cloudflare-hosted mockup link on their phone during the call.
- Demo flow: Aubrey dials from GHL → books via calendar link → Camille builds mockup and deploys to Cloudflare Pages → Camille sends teaser email with live link → John calls at booked time → closes.
- Offer: $750 setup + $297/month (website, hosting, maintenance, local SEO basics, enquiry capture, missed-call follow-up).
- GHL: 5 disposition-based workflows (WF1 Demo Booked, WF1A No Show, WF2 No Answer, WF3 Mockup Requested, WF4 Incorrect Number, WF5 Not Interested).
- Caller pay: $5/hour trial via Jibble. Weekly bonus from week of June 23 based on Qualified Phone Demos Completed (0–4=$0, 5–9=$5, 10–14=$10, 15+=$20). $30 per signed client on first Stripe payment.
- Source of truth for all ops:
workflows/us-trades-website-pivot-workflow.md
Locked demo-generation plan:
- Reference plan name: Business Website Demo Generator (MVP — US Contractors / Home Services).
- Purpose: generate asset-driven, mobile-first homepage mockups for US contractors/home services businesses using real business assets, Google review proof, services, location, phone, and trade-specific conversion structure.
- V1 scope: warm demo machine only: single-page homepage, desktop/mobile screenshots,
loom-opener.txt,what-changed.txt,audit.json, andqa-report.md. - V2 scope: production site generator only after signed agreement and payment; use V1 learnings to generate full service pages, schema, hosting/deploy steps, and GHL integration.
- First test batch: Florida roofers from
aurea-lead-generator/us_trades_leads.csv, while keeping the architecture sector-adaptive for plumbers, electricians, HVAC, landscapers, remodelers, concrete/paving, pressure washing, and generic contractors. - Planned tools:
tools/collect_business_assets.py,tools/generate_business_demo.py,tools/generate_business_site.py, and sector adapters undertools/business_types/*.yml. - Quality rule: Dr Winter remains a polish/credibility reference, not the trades template. Contractor demos must be direct, mobile-first, and built around calls, text, quote requests, estimates, inspections, urgency, local proof, and project photos.
- Premium contractor rule: the quality gate is not "passes QA." The quality gate is "would I be proud to screen share this with the owner on Zoom?" Tampa Bay Pavers proved that bespoke hand-polish beats generator output at this stage.
- Contractor reference templates live at
/Users/johntossou/Desktop/CONTRACTORS WEBSITES/DEMO-TEMPLATE-V1and/Users/johntossou/Desktop/CONTRACTORS WEBSITES/DEMO-TEMPLATE-V2. Use them as the premium pattern library for future contractor mocks. - Proof rule: never invent reviews, licenses, insurance, years in business, awards, credentials, or before/after results. Render only source-mapped proof; otherwise use logged placeholders or safer neutral language.
1. Core Thesis
The opportunity is not "selling websites."
The stronger opportunity is:
Build a repeatable local visibility system for small businesses: a clean website, local SEO foundations, review trust, enquiry capture, maintenance, and later automation.
The website is the visible object. The business value is:
- more trust
- better Google visibility
- better conversion from visitors to enquiries
- fewer missed enquiries
- a cleaner professional presence
- a recurring support layer the owner does not want to manage
AI matters because it changes the delivery economics:
- research is faster
- first drafts are faster
- mockups can be generated before the call
- service pages can be templated and adapted
- local SEO pages can be produced systematically
- CRM/review/automation setup can be repeated
- one small team can deliver what used to require several specialists
The play is to combine:
- the English video's low-friction, recurring, high-volume model
- the French video's premium trust, proof, content, and inbound model
- Aurea's existing GHL, landing page, clinic, and automation experience
2. The Two Video Models
2.1 English Video Model: Low-Ticket Website + Monthly Retainer
The English video describes an agency that initially sold simple websites to contractors at low monthly prices.
Key mechanics:
- target Google Maps businesses
- call or SMS at high volume
- use a simple hook: "I made a website example for you. Want to see it?"
- sell a low-friction base package around $147-$297/month
- keep the first product simple
- add Google Business Profile optimization, reviews, missed-call text-back, lead follow-up, SEO, LSA, and automation later
- make the offer cheap enough that the owner can try it without a massive buying committee
- build recurring revenue first, then upsell existing clients
Strategic lessons:
- do not overbuild before getting clients
- cold calling builds the sales skill faster than passive channels
- monthly recurring revenue creates pressure relief once it compounds
- filtering improves later: reviews, verified Google profile, phone number, and real demand matter
- low-ticket entry creates trust, then upsells become easier because the card and relationship already exist
Best use for Aurea:
- cash-speed model
- caller training model
- Google Maps prospecting model
- no-show reduction through a tangible mockup
- recurring retainer logic
2.2 French Video Model: Premium Website + Authority + Inbound
The French video analyzes Max Share / Share Agency, a web agency reportedly generating around EUR400,000/month by selling website creation and adjacent services.
Key mechanics:
- core service: showcase websites, usually around EUR4,000-EUR8,000
- target ordinary SMEs around EUR500k-EUR5m turnover
- add maintenance as the first recurring service
- add SEO and Google Ads as traffic-generation services
- use Instagram short-form content as the main acquisition engine
- recycle the same short-form content to YouTube and LinkedIn
- create videos where the agency critiques, repairs, or redesigns real websites
- boost best-performing Instagram content with ads
- use comments and website URLs from the content as prospecting inventory
- use a lead magnet: checklist to diagnose whether a website is good or bad
- use case studies, reviews, process explanation, and proof heavily on the agency website
Strategic lessons:
- one-shot website fees create immediate cash
- maintenance/SEO/ads create recurring revenue
- visible expertise is a lead-generation asset
- showing before/after website improvements lets prospects visualize their own result
- a website agency's own site must demonstrate authority and proof
- content + ads can create warmer leads than pure cold outreach
- a lead magnet can educate prospects before the call
Best use for Aurea:
- authority model
- offer architecture model
- proof and case study model
- content/inbound strategy
- premium pricing direction after early validation
2.3 Combined Model for Aurea
The two models are not contradictory. They are two ends of the same system.
Use the English model for speed:
- Google Maps scraping
- cold call/SMS
- quick mockup
- low-friction call
- low setup fee + monthly retainer
Use the French model for authority:
- before/after content
- audit/checklist lead magnet
- visible portfolio
- case studies
- proof-led own website
- premium package later
The combined offer should not start as pure EUR4,000-EUR8,000 websites. That is too slow for Aurea's current cash-constrained position.
Recommended starting structure:
- setup fee: GBP500-GBP1,500
- monthly retainer: GBP250-GBP500/month
- optional premium website build: GBP2,500-GBP5,000 once proof and demand are stronger
- automation upsell later: GBP300-GBP1,000/month depending on scope
3. Offer Architecture
3.1 The Offer Frame
Do not say:
We build websites.
Say:
We build and maintain a clean local website that makes you easier to find on Google, easier to trust, and easier to contact, without you dealing with designers, developers, SEO people, or tech.
Short version:
A better local website, maintained for you, built to turn Google searches into enquiries.
For trades:
We help local trades turn Google searches into quote requests with a clean website, review proof, service pages, and enquiry capture.
For clinics:
We help clinics turn treatment searches into trusted enquiries with a clean website, review proof, compliant treatment pages, and fast follow-up.
3.2 Core Package
The first product should be simple enough to deliver repeatedly.
Core deliverables:
- one responsive local business website
- homepage
- service pages or treatment pages
- about/credentials section
- review/testimonial section
- Google review link or review funnel
- enquiry form
- click-to-call
- basic local SEO setup
- technical hosting/maintenance
- analytics/search console where practical
- monthly small edits included
Optional add-ons inside base package:
- GBP profile optimization
- missed-call text-back
- lead notification by SMS/email
- FAQ section
- structured data/schema
- simple monthly performance snapshot
3.3 Retainer
The recurring offer is the real business.
Maintenance retainer can include:
- hosting
- uptime/basic checks
- backups
- plugin/theme updates if WordPress is used
- small content edits
- form checks
- review link/funnel maintenance
- monthly SEO hygiene
- GBP support
Local SEO retainer can include:
- one new service/location page per month
- page title/meta refresh
- internal links
- Google Business Profile posts
- review-generation reminders
- citation checks
- simple ranking/search visibility reporting
Automation retainer can include:
- missed-call text-back
- web form follow-up
- lead reminder sequence
- review request automation
- WhatsApp/SMS triage
- AI voice receptionist for suitable clients
3.4 Upsell Ladder
The model should ladder naturally.
Entry:
- free or low-cost website audit
- quick mockup
- diagnostic checklist
Core sale:
- website setup + monthly maintenance
First upsell:
- local SEO
- GBP optimization
- review system
Second upsell:
- Google Ads / LSA / search campaign support
Third upsell:
- AI receptionist
- missed-call recovery
- AI chat/WhatsApp triage
- CRM pipeline automation
The order matters. Sell trust and visibility before selling automation. Owners buy automation more easily once they trust that the website and lead capture actually work.
4. Pricing Models
4.1 Low-Ticket Recurring Model
Inspired by the English video.
Example:
- GBP0-GBP500 setup
- GBP250-GBP350/month
- 12-month minimum optional, or monthly with setup fee
Pros:
- easier to sell
- less decision friction
- fast MRR compounding
- good for cold call volume
Cons:
- requires many clients
- lower cash upfront
- churn risk if value is not visible
- support load can creep
Use when:
- selling to smaller businesses
- early testing
- no strong authority yet
- caller needs simple pitch
4.2 Hybrid Setup + Retainer Model
Recommended for Aurea's first serious test.
Example:
- GBP750 setup
- GBP297/month maintenance + local SEO basics
Alternative:
- GBP1,500 setup
- GBP350/month maintenance + monthly SEO page
Pros:
- cash upfront
- recurring value
- less dependency on huge client count
- easier to fund fulfillment
Cons:
- slightly harder close
- mockup/proof must be stronger
- owner must believe the site is worth maintaining
Use when:
- prospect has reviews and demand
- current website is weak or absent
- one customer/job has meaningful value
4.3 Premium One-Shot + Retainer Model
Inspired by the French video.
Example:
- GBP3,000-GBP6,000 website build
- GBP300-GBP800/month maintenance/SEO
Pros:
- strong cash collection
- fewer clients needed
- higher perceived quality
Cons:
- needs authority and proof
- harder cold call close
- longer sales cycle
- higher delivery expectations
Use when:
- prospect has real budget
- company does GBP500k+ revenue
- case studies exist
- inbound/content created trust before call
4.4 Pricing Recommendation for Now
Start with:
GBP750 setup + GBP297/month
Position:
- website build
- hosting/maintenance
- review section/funnel
- enquiry form
- basic local SEO setup
- monthly small edits
Then upsell:
- GBP500 one-time GBP optimization
- GBP500/month SEO
- GBP500/month Google Ads/LSA management
- GBP300-GBP1,000/month AI automation depending on complexity
Do not start with a free website unless the retainer term is clear. Free work without commitment creates cash pressure and weak buyers.
Locked cash protection rules:
- Stripe auto-debit from Day 1.
- No work begins until the first payment is live.
- Retainer billing starts on the agreed start date even if the client delays assets, photos, copy, logins, domain access, or Google Business Profile access.
- This must be stated in the agreement. Client delays cannot control Aurea cash flow.
- Avoid "soft starts." Soft starts turn into unpaid custom work.
Optional stronger package for better-fit buyers:
GBP1,500 setup + GBP397/month
Use this when:
- the buyer has stronger proof of demand
- the business is team-led, not a fragile solo operator
- one extra client/job covers the monthly retainer
- the demo and competitor audit reveal obvious missed revenue
4.5 Two-Offer Contrast Close
Use a contrast close instead of only presenting one price.
Example:
Option 1: We can build the site as a one-off project for GBP3,500, then hand it over. You would manage hosting, edits, reviews, forms, and SEO separately.
Option 2: We build it for GBP750 setup, then maintain it for GBP297/month. That includes hosting, small edits, enquiry capture, review support, and local SEO basics. You also get a 3-month exit door if it is not working.
Why this works:
- the high one-off price anchors the value
- the retainer becomes the logical, lower-friction choice
- the 3-month exit door lowers perceived risk
- auto-debit protects the business from slow-pay clients
Do not use the 3-month exit door as an excuse to accept weak buyers. It is a risk-reversal device, not a replacement for qualification.
5. Niche Selection
5.1 Do Not Target "Any SMB"
"Any SMB without a website" is too broad.
Problems:
- scattered scripts
- scattered templates
- scattered proof
- scattered objections
- hard caller training
- weak learning loop
Start with one or two niches where the website has obvious economic value.
5.2 Best First Niche: Local Trades / Home Services
Examples:
- roofers
- plumbers
- electricians
- driveway installers
- patio installers
- landscapers
- garden room builders
- bathroom fitters
- kitchen fitters
- decorators
Why this niche has natural demand:
- customers search on Google
- one job can be worth thousands
- reviews matter
- local visibility matters
- quote forms and phone calls are natural
- many businesses have weak websites
- before/after photos make redesign demos persuasive
- business owners understand missed enquiries
Best prospect signals:
- 10+ Google reviews
- rating 4.5+
- verified Google Business Profile
- phone number listed
- no website or poor website
- clear service area
- active recent reviews
- photos of jobs
Avoid:
- zero-review businesses
- unverified profiles
- passive/semi-retired operators
- businesses with no recent reviews
- very low-value services
5.3 Secondary Niche: Clinics / Aesthetics / Dental
Why this can work:
- trust is central
- high-value treatments
- credentials and reviews matter
- treatment pages need clarity
- John has existing domain knowledge
- current clients already show website/SEO/maintenance demand
Evidence:
- Minura: website pain appeared naturally
- Kelsey: retainer evolved into website/SEO/reviews/newsletter/support
- Andrew Winter: strong no-website signal, but no-show risk
Risks:
- solo operators can be fragile
- no-shows
- compliance sensitivity
- cash constraints
- high-touch expectations
Use clinics only when:
- reviews show real demand
- owner is active and growth-minded
- website need is obvious
- call commitment is strong
- budget is not clearly distressed
- the business is not purely dependent on one overwhelmed solo operator
- marketplace/direct booking economics are visible
Clinic-specific ROI angle:
For clinics using Fresha, Treatwell, or similar marketplaces, calculate marketplace commission leakage.
Core pitch:
If you are paying 20-30% commission on bookings through [marketplace], a direct booking website can pay for itself by shifting even a small number of bookings back to your own funnel.
Use this when:
- the clinic already pays marketplace commissions
- the service ticket is high enough
- direct booking is realistic
- the website can include clear treatment pages, trust proof, and booking/enquiry capture
This angle can be stronger than generic "better SEO" because it turns the website into commission recovery, not design work.
5.4 Niche Decision Rule
Choose a niche where this sentence is obviously true:
If this business got 2-3 more good enquiries per month, the website and retainer would pay for itself.
If that is not true, do not target the niche.
Locked niche rule:
Do not target "all SMBs." Target high-ticket local businesses with:
- proven demand
- review proof
- weak/missing website
- owner or decision maker reachable by phone
- operational capacity to handle more enquiries
- enough margin that one client/job pays for the system
Trades should be tested before property management / real estate. Property management and real estate can be saturated, slower-cycle, and less aligned with the cold-call mockup motion.
Do not reuse clinic assumptions inside trades.
Trades:
- owner-led or small-team businesses
- owner often answers the phone directly
- gatekeeper blockade is usually not the main issue
- review bar can be lower: 15-30 reviews with 4.5+ can already prove real demand in many UK towns
- sales hook should focus on quote requests, missed calls, local trust, and service-area visibility
Clinics:
- team-led or premium solo only
- gatekeepers and receptionists can block access
- review bar should be higher: 50-100+ preferred, with 4.5+ rating
- marketplace leakage can be a major ROI angle when using Fresha, Treatwell, or similar
- sales hook should focus on direct booking, trust, premium patient enquiry capture, and reducing platform commission
6. Lead Scoring
Every prospect should be scored before being pushed to callers or GHL.
6.1 Website Opportunity Score
Score 0-100.
Positive signals:
- no website listed
- website is broken, ugly, slow, or generic
- website has weak mobile layout
- no clear CTA
- no quote/contact form
- no service pages
- no review proof
- no location/service area clarity
- no tracking/lead capture
Negative signals:
- strong modern website
- strong SEO pages already
- clear conversion flow
- high-end agency-level design
6.2 Demand Proof Score
Positive signals:
- Trades: 15-30+ reviews can be enough if rating is 4.5+ and reviews are recent
- Clinics/private healthcare: 50-100+ reviews preferred, especially for premium positioning
- recent reviews
- rating above 4.5
- business photos
- owner replies to reviews
- active GBP
- clear service area
- existing phone demand
Negative signals:
- zero reviews
- no recent activity
- bad reviews about reliability
- closed/temporary hours
- unclear service
6.3 Commercial Fit Score
Positive signals:
- high-ticket jobs or treatments
- local search intent
- repeatable services
- strong owner benefit from more leads
- simple buying journey
Negative signals:
- very low-ticket service
- unclear monetization
- seasonal only
- purely referral-based business
6.4 Outreach Priority
Priority A:
- weak/no website
- trades: 15-30+ reviews with 4.5+ rating
- clinics/private healthcare: 50-100+ reviews with 4.5+ rating
- verified GBP
- high-value service
- clear phone number
- recent activity
Priority B:
- website exists but poor
- trades: 5-15 reviews if other signals are strong
- clinics: below 50 reviews only if the clinic is clearly premium, team-led, or commercially mature
- high-value service
- visible need
Priority C:
- weak signals, uncertain urgency
Do not book Priority C until the model is proven.
7. AI Website Creation Workflow
7.1 The Principle
The website should be AI-assisted, not AI-sloppy.
AI should accelerate:
- research
- structure
- first copy
- service pages
- schema
- FAQ
- design exploration
- competitor review
- SEO keywords
- audit notes
Human judgment should control:
- positioning
- credibility
- final design taste
- claims
- service accuracy
- proof
- conversion logic
7.2 Pre-Call Mockup Workflow
For outbound, do not build a full custom website before sale.
Build a lightweight demo:
- business name
- service category
- location
- review proof
- 3-5 services
- hero section
- review/Google section
- enquiry form section
- CTA
The goal is to create curiosity and meeting attendance, not to finish delivery.
Time rule:
- Do not optimize around an artificial "8-minute mockup" target.
- The real rule is no full custom build before payment.
- For a serious Priority A prospect, a 20-30 minute personalised mockup screenshot is acceptable if it materially increases show rate.
- Stop before unpaid delivery work: no full site, no custom code, no deep integrations, no SEO implementation, no domain work.
Mockup levels:
Level 1: screenshot-style static mockup
- fastest
- good for teaser
- no hosting needed
Level 2: one-page live demo
- stronger for calls
- use reusable template
- personalize business name, location, services, reviews
Level 3: deeper mini-site
- only for high-priority prospects
- homepage + 1 service page
Recommended for testing:
- Level 2 for Priority A prospects
- Level 1 for broader outreach
7.3 Research Inputs
Before generating a mockup, collect:
- business name
- GBP category
- location
- phone
- website URL if any
- reviews
- review count/rating
- top services
- service area
- photos
- current CTA
- competitors ranking nearby
AI prompt structure:
You are creating a quick local website mockup for [Business Name], a [category] in [location].
Use these facts:
- Services:
- Review themes:
- Business strengths:
- Current website weakness:
- Local competitors:
Create:
1. Hero section headline/subheadline
2. CTA
3. 4 service cards
4. Review/trust section
5. Why choose us section
6. FAQ
7. Local SEO title/meta
Tone: clear, local, credible, no hype.
7.4 Website Structure
Minimum viable local website:
- Hero
- category + location
- outcome
- CTA
-
trust signal
-
Proof
- reviews
- years experience if known
-
photos/results/projects
-
Services
- service cards
-
link to service pages
-
Why choose us
- practical differentiators
-
no fake claims
-
Process
- how enquiry/quote/booking works
-
reduces uncertainty
-
Local areas served
-
relevant for trades
-
FAQ
-
price, timing, service area, how to book
-
CTA section
- call
- form
-
WhatsApp if relevant
-
Tracking and lead capture
- form notification
- GHL contact
- missed-call flow where possible
7.5 AI Quality Rules
Never publish AI copy that:
- invents credentials
- invents years in business
- invents awards
- invents case studies
- invents prices
- makes medical or legal claims without verification
- uses generic filler like "your trusted partner"
- says "AI-powered" when the buyer wants a practical business result
Good copy is:
- specific
- short
- local
- proof-led
- service-led
- conversion-led
7.6 Design Rules
For the first offer, design should be:
- clean
- fast
- mobile-first
- trustworthy
- easy to scan
- not overdesigned
Local business websites should not feel like SaaS landing pages. They should make a buyer trust the business quickly and contact them easily.
Avoid:
- giant abstract hero sections
- fake stock photos
- excessive gradients
- tiny CTAs
- no phone number above fold
- generic icons replacing real proof
- design that hides services
Use:
- real work photos
- review snippets
- location/service-area clarity
- clear phone CTA
- simple forms
- strong mobile layout
8. Sales Script
Script principle:
Use ownership, specificity, and visible proof. Do not overclaim. If it is a mockup, call it a website example or mockup, not a finished website.
The desired tone is:
- specific
- useful
- already did some work
- grounded
- not hype-heavy
Keep the pressure in the maths, not in the personality.
8.1 Cold Call Opening
Primary version for trades:
Hi, is this [Business Name]?
Quick one. I made a website example for you using your real reviews, services, and area.
It looks a lot stronger than what people see on Google right now.
Takes 10 minutes to show you. Worth a look today?
If yes:
Perfect. I will show you the homepage, the review section, and the enquiry flow.
If you like it, I can explain how we build and maintain it. If not, no problem.
Are you around today or tomorrow?
Loss-frame follow-up if they engage:
The reason I made it is simple: even businesses with weaker reviews can still win the Google search if their site makes it easier to call or enquire.
Do not say "competitors with weaker reviews than yours" unless it has been verified.
Clinic/Fresha version:
Hi, is this [Business Name]?
Quick one. I noticed you are taking bookings through [Fresha/Treatwell], and I made a direct-booking website example for you using your real treatments, reviews, and location.
The point is to help more patients enquire directly, instead of every booking being taxed by the marketplace.
Takes 10 minutes to show you. Worth a look today?
8.1.1 SMS Before First Call
Hi [Name], I made a website example for [Business] using your real reviews, [location], and services.
Looks proper. The idea is to help more Google visitors call or enquire directly.
10 minutes to show you. Free today?
8.1.2 SMS After Missed Call
Hi [Name], I made a website example specifically for [Business].
Your reviews are already on the homepage.
I will keep the mockup live for 72 hours, then recycle the slot for the next business in [area].
10 minutes. Free today or tomorrow?
The 72-hour hold is only allowed if true. It means the demo slot/mockup is not kept indefinitely, not that the prospect is being artificially threatened.
8.2 If They Ask "Is This a Sales Call?"
Fair question. I do build these for businesses, yes. But I am not asking you to decide anything on this call. I already made a quick example, and I just want to show you what I mean visually. If it is not useful, no problem.
8.3 If They Already Have a Website
That is exactly why I made the example. This is not about having a website or not. It is about whether the site is helping people trust you and enquire when they find you on Google.
8.3.1 Clinic Marketplace Angle
Use this only for clinics, salons, or aesthetic businesses that clearly rely on Fresha, Treatwell, or similar booking marketplaces.
Do not bury this angle. It can be the strongest clinic-specific ROI frame because the prospect already knows the commission pain.
I noticed you are taking bookings through [Fresha/Treatwell]. That works, but it also means you are giving away roughly 20-30% on bookings that could come directly through your own website.
The example I made is not just a nicer website. It is a direct booking route, so more patients can find you, trust you, and enquire without every booking being taxed by a marketplace.
If they say marketplace bookings are already working:
That is good. I would not remove it immediately. The point is to build your owned channel alongside it, so over time you keep more of the patients you already deserve instead of paying commission forever.
8.4 If They Say Send It Over
Best response:
I can send a screenshot now so you can see it is real.
But the part worth seeing is the enquiry flow and missed-call text-back. I want to show how it works live, otherwise it will not make sense.
5-10 minutes. Can we do [time]?
Optional teaser:
Here is one screenshot, just the homepage.
I want to show you the enquiry form and missed-call text-back live on the call. That is the part worth seeing.
Never send the full enquiry flow before the call. Preserve curiosity and give them a reason to attend.
8.5 Confirmation Message
Confirmed for [time].
I will show you the [Business Name] homepage, your reviews integrated in, the service layout, and the enquiry form.
One other thing I noticed on your Google profile I want to show you too. Takes 30 seconds.
See you then.
8.6 Pre-Call Reminder
Still good for [time]?
Your [Business Name] site example is ready. I have your [X] reviews on the homepage.
See you then.
8.7 Call Structure
- Start with permission
I will show you what I built, then explain the thinking, then if it makes sense I will show you how we build and maintain it. Sound fair?
- Discovery and mental accounting
When a call comes in while you are on a job, what happens?
After they answer:
How many times does that happen in a week?
Then:
So at roughly [average job value], that is about [maths] in missed revenue every month. And that is only the calls you know about.
For clinics:
What is the average value of one new patient or treatment booking?
If they use Fresha/Treatwell:
And how much of that goes to the platform on a marketplace booking?
- Show current state and contrast
Before I show what I built, here is what someone searching for [service] in [area] sees right now.
Show:
- Google profile
- current/no website
-
weak CTA or missed opportunity
-
Show mockup mobile-first
This is what they see instead.
Start with mobile view.
- hero
- reviews
- services
- enquiry flow
- sticky call button
- proof near the top
Use the mobile reveal because most local searches happen on phones.
-
Explain value
-
easier to trust
- easier to find
- easier to enquire
- maintained for them
- captures more direct enquiries
-
reduces missed-call leakage
-
Offer
We can build this properly, connect the enquiry form, host and maintain it, and make monthly SEO/review updates for [price].
- Close
You said missed calls are costing you roughly [their number].
You said one extra [job/patient] covers this easily.
You said this looks more credible than what people see now.
So the only thing to decide is whether we start now or leave it for later.
Setup is [setup]. It is [monthly] after that for hosting, maintenance, and the enquiry system.
I can have this live in [timeframe]. I will send the Stripe agreement now; once that is live, we start.
If they stop you, handle the real objection. Do not invite hesitation with "does that sound good?" after the value is already clear.
Avoid saying "the decision is already made." That can create reactance. The better frame is: they already agreed to the maths, so the only real decision is timing.
8.8 Objection Responses
"I already have a website"
I saw it. Your reviews are strong; that is the hard part.
The site just does not do enough with them. Visitors land, but there is not a clear enough next step, form, or missed-call safety net.
One extra enquiry a month from that traffic can pay for this.
"Just send the link"
I can send a screenshot now so you can see it is real.
But the part worth seeing is the enquiry flow. I want to show you how a missed call triggers an instant text and how the form routes the enquiry.
That is the bit that makes the difference. 5 minutes. [Day/time]?
"Too expensive"
What is your average job value?
After they answer:
So one job this system captures covers the year in one go.
You are not really paying [monthly] a month. You are paying for one captured job to trigger the rest for free.
Is the price the issue, or is it that you are not sure it will capture leads?
"I need to think about it"
Of course. Usually it is either the setup fee or whether it will actually work. Which one is it?
After they answer:
That makes sense. I will keep the mockup live for 72 hours. After that, I recycle the slot for the next business in [area].
I will send you the screenshot now so you have something concrete to look at.
"I had a bad experience with a marketing agency"
Most agencies deserve that reputation. I will not pretend otherwise.
The difference here is that if you cancel, you keep your domain and we keep the offboarding clean.
The 90-day exit means you can test it before committing long term. You are not being held hostage.
"Treatwell/Fresha already gives me leads"
It does. And it takes [20-30]% of every booking for it.
We build you an owned channel: no commission, no platform dependency, no algorithm change wiping out your bookings.
At [average booking value], how many direct bookings a month would you need to cover [monthly] and come out ahead?
Let them calculate it. The number is stronger when they say it.
9. No-Show System
No-shows are a value problem before they are a calendar problem.
The prospect must believe there is something specific waiting for them.
Rules:
- Name the meeting around the object
- bad: "website review"
-
good: "showing the website example I made for [Business]"
-
Keep it short
-
10 minutes is enough for the first show
-
Use a screenshot teaser
- preserves curiosity
- proves work was done
-
reduces ghosting
-
Confirm the payload
- homepage
- services
- reviews
-
enquiry form
-
Filter harder
- no reviews = low priority
- no urgency = low priority
-
no clear owner/contact = low priority
-
Call before Zoom if needed
-
do not rely only on calendar invites
-
Track show rate by script angle
- "website example" vs "website audit"
- screenshot vs no screenshot
- 10-minute call vs 20-minute call
10. Acquisition Channels
10.1 Cold Outreach: Fast Cash Channel
Use Google Maps first.
Lead criteria:
- target category
- target location
- review count
- verified GBP if detectable
- phone number
- no/weak website
- commercial fit
Cold channels:
- call
- SMS before/after call
- email if available
- WhatsApp where appropriate
First campaign goal:
- prove bookings and show rate
- not build perfect automation
Track:
- dials
- connects
- positive responses
- calls booked
- shows
- closes
- no-shows
- objections
- niche
- website status
- review count
10.2 Inbound Content: Authority Channel
Inspired by Max Share.
Content format:
"I would improve this [niche] website by changing these 3 things."
Examples:
- "How I would fix this roofer's website so quote requests are easier"
- "This clinic has great reviews but the website is hiding the trust"
- "This driveway installer could turn more Google searches into calls with these changes"
- "Before/after: making this local business homepage clearer in 60 seconds"
Content structure:
- Show the current website or Google profile
- Name one visible issue
- Show the improved mockup
- Explain why it helps conversion/trust
- CTA: "Comment your website and I will review one each week"
Recycling:
- Instagram Reels
- TikTok
- YouTube Shorts
Paid boost:
- boost only the best organic posts
- target local business owners or niche-specific interests
- use comments and profile visits as lead signals
10.3 Lead Magnet
Inspired by the French video.
Lead magnet:
Website Diagnostic Checklist
Purpose:
- educate prospects
- capture name/email/website
- make them self-diagnose
- create a reason for sales follow-up
Checklist sections:
- does the site explain what you do in 5 seconds?
- is the phone number visible above the fold?
- are reviews visible?
- are services clear?
- is there a contact form?
- is it mobile-friendly?
- does it mention service area/location?
- does each service have its own page?
- does the site load quickly?
- does it tell visitors what happens after they enquire?
Follow-up:
I saw you downloaded the website checklist. I took a quick look at your site and noticed [specific issue]. Want me to show you what I would change?
11. Proof System
The agency website and sales process must be proof-led.
11.1 Proof Assets to Build
Minimum:
- 3 demo sites by niche
- 3 before/after mockups
- 5 screenshots of improved sections
- one clear pricing page or package page
- one "how it works" process page
- one checklist lead magnet
After clients:
- Google reviews
- client testimonials
- screenshots of traffic/enquiries
- before/after website case studies
- delivery timeframe
- service pages ranking progress if available
11.2 Case Study Template
Client:
Niche:
Problem:
Old website issue:
What we changed:
Timeline:
Result:
Package:
Screenshots:
11.3 Agency Website Requirements
The agency's own website must demonstrate the product.
Above the fold:
- clear value proposition
- proof/reviews
- CTA
- portfolio signal
Main page:
- what we build
- why it helps enquiries
- examples
- process
- packages
- FAQ
- lead magnet
- booking CTA
Avoid:
- vague "digital growth agency" language
- no proof
- no pricing anchor
- no examples
- unclear process
12. Fulfillment SOP
12.1 Delivery Stages
Stage 1: Intake
- business details
- services
- service area
- photos
- reviews/testimonials
- phone/email
- existing domain
- brand assets
- competitors
Stage 2: Research
- GBP review themes
- competitors
- local keywords
- existing website audit
- service structure
Stage 3: Draft
- page structure
- copy
- design
- service pages
- forms
Stage 4: Review
- internal QA
- client review
- edits
Stage 5: Launch
- domain
- hosting
- forms
- GHL contact creation
- notifications
- analytics
- Search Console
Stage 6: Retainer
- maintenance
- monthly edits
- SEO/review tasks
- reporting
- upsell monitoring
12.2 AI-Assisted Build Checklist
Use AI to generate:
- homepage copy
- service page drafts
- FAQs
- meta titles/descriptions
- schema suggestions
- review summary themes
- competitor positioning
- call scripts
- confirmation SMS
- case study draft
Human must verify:
- claims
- services
- locations
- prices
- credentials
- compliance
- tone
- design quality
12.3 Tech Stack Options
Fast static site:
- Claude/Codex
- HTML/CSS/JS or lightweight framework
- Cloudflare Pages
- GHL forms/workflows
GHL site:
- fastest integration
- simpler for CRM
- less design/code flexibility
WordPress:
- familiar to clients
- plugin maintenance burden
- useful if client wants CMS access
Recommendation:
- use static/Cloudflare or GHL for v1
- do not overcomplicate CMS unless client explicitly needs it
- keep ownership/maintenance terms clear
12.4 Team Accountability
John owns:
- niche selection
- offer strategy
- sales calls and closes
- pricing decisions
- client retention and upsells
Camille owns:
- lead list hygiene
- prospect scoring against the current niche rules
- mockup preparation from approved templates
- GHL setup and standard workflow QA
- daily caller KPI checks
- daily call disposition review
- script QA and off-script flagging
- escalation to John when the caller misses volume, books poor-fit demos, or stops reporting
Caller owns:
- daily call volume
- accurate dispositions
- using the approved script
- booking qualified 10-minute demos
- sending approved confirmations
No repeat of the Norman failure mode:
- missing updates for 24 hours is an escalation
- missing updates for 48 hours is a replacement trigger unless there is a clear emergency
- Camille checks the caller daily so John does not discover a dead pipeline after several days
Caller hire outreach script:
Hi [Name],
Hiring one cold caller this week for a UK-based role.
Calls go to local businesses: plumbers, roofers, trades.
Simple pitch. Paid base + GBP25-50 per demo you book.
Looking at 3 people this week. 5-minute call if you are keen:
[link]
Why this works:
- one role this week creates real scarcity
- "5-minute call" lowers activation energy
- niche specificity tells them exactly what they are walking into
- base + per-demo incentive filters for performance
13. Automation Upsells
Do not lead with "AI automation" for most local businesses. Lead with:
- missed enquiries
- slow replies
- no review flow
- poor follow-up
- admin load
Then sell automation as the solution.
13.1 Easy Automation Upsells
- missed-call text-back
- form enquiry auto-reply
- new lead SMS to owner
- review request after job/treatment
- simple reactivation message
- appointment reminder
- quote follow-up
13.2 Advanced Upsells
- AI chat triage
- WhatsApp triage
- AI voice receptionist
- CRM pipeline
- quote workflow
- lead scoring
13.3 Clinic-Specific Automation
Use lessons from the clinic omnichannel stack:
- GHL as CRM/unified inbox
- Appointwise for chat triage
- Vapi for voice
- Twilio for phone infrastructure
- ElevenLabs only when voice clone is needed
- beware WhatsApp voice call limits
- do not overpromise platform integration
For clinics, automation must be framed as:
protecting the diary and responding faster to enquiries
not:
cool AI system
14. Operating Metrics
Track the business like a funnel.
14.1 Outreach Metrics
- leads scraped
- leads qualified
- dials
- connects
- positive responses
- demos booked
- demos shown
- no-show rate
- closes
- revenue collected
- monthly recurring revenue added
14.2 Fulfillment Metrics
- build time
- revision count
- launch time
- support tickets
- monthly edit load
- gross margin
14.3 Retainer Metrics
- MRR
- churn
- upsell rate
- client health
- review generation
- lead form submissions
- calls/clicks if tracked
14.4 Content Metrics
- short-form posts
- views
- comments with URLs
- inbound audits requested
- lead magnet downloads
- calls booked from content
- ad spend per booked call
15. 14-Day Test Plan
Day 1-2: Choose Niche and Build Template
- pick one niche
- build one demo template
- create script
- define scoring
- define package/pricing
Day 3-4: Build Lead List
- scrape 200-500 Google Maps prospects
- score by reviews, website weakness, verified profile, phone
- select 50 Priority A leads
Day 5-7: Create Mockups
- create 10-20 quick mockups
- use screenshot teaser
- prepare call walkthrough
Day 8-12: Call/SMS
- call 50-100 prospects
- book 10-minute demos
- track show rate
- test script variants
Day 13-14: Review
Evaluate:
- connect rate
- booked call rate
- show rate
- close rate
- strongest objections
- best niche signals
- delivery time per mockup
Decision:
- continue niche
- adjust niche
- adjust script
- adjust pricing
- build more automation
Do not judge the whole model from 10 calls. Judge early scripts from 50-100 conversations and at least 10 booked demos.
15.1 Kill-Switch and Diagnostic Rules
Do not use "2 closes in 30 days" as the only kill-switch. It is aspirational, not diagnostic.
Use leading indicators:
- 100 dials, 0 positive interest: fix script delivery or niche targeting immediately.
- 200+ dials, 0 demos booked: exit or radically change the niche/script.
- 10+ demos booked, 0 shows: confirmation/no-show system is broken.
- 10+ demos shown, 0 closes: pricing, demo structure, authority, or offer framing is broken.
- Demos show strong interest but no payment: close/payment discipline is broken.
Thirty-day model rule:
If after 30 days and 200+ quality dials there are zero demos booked, the current niche/script combination is not working. Do not keep grinding it unchanged.
This does not automatically mean the whole pivot is dead. Diagnose the funnel stage before abandoning the model.
16. Rules for Aurea
- Do not do unpaid deep custom work.
Mockups should be lightweight and templated.
- Do not target fragile buyers first.
Prioritize businesses with reviews, demand, and commercial urgency.
- Do not make AI the headline.
Use AI internally. Sell visibility, trust, enquiries, and maintenance.
- Do not sell ads first.
Ads recreate the pressure of the old model. Sell website/maintenance first, then traffic.
- Do not overbuild automation before client demand.
Start with website + review/enquiry basics. Add AI receptionist/automation after trust.
- Do not choose a niche only because it is familiar.
Clinics are familiar, but trades may be cleaner for the first test.
- Keep the meeting object-specific.
"I will show you the website example I made for your business" is stronger than "let's discuss your website."
- Make every client a future case study.
Capture before/after, timeline, review, and result from day one.
- Gate effort by prospect stage.
Use quick mockups to book the call. Use deep competitor audits and ROI math only for confirmed/high-intent calls. Do not recreate the old custom-work trap.
- Protect cash flow with payment discipline.
Auto-debit is mandatory. No payment, no work. Billing starts even if the client delays assets.
- Do not build dependence in a toxic way.
The system should be sticky because it delivers recurring value, not because the client is trapped. Keep offboarding terms clean for domain, assets, and website ownership.
-
Answer the three live founder questions before launch.
-
Are you building systems to avoid making calls?
- Can you survive 60 days on this cash flow without a job?
-
Will you fire a caller quickly if they miss KPIs?
-
Stop asking for abstract interest.
Do not ask "are you interested?" before the prospect has seen value. Make the next step feel like the natural default:
- "Worth a look today?"
- "5-10 minutes. Can we do [time]?"
- "I will send the Stripe agreement now; once that is live, we start."
The goal is not to pressure people into a bad decision. The goal is to make inaction feel like actively letting go of a useful asset.
17. Reference Scripts
SMS Before Call
Hi [Name], I made a website example for [Business] using your real reviews, [location], and services.
Looks proper. The idea is to help more Google visitors call or enquire directly.
10 minutes to show you. Free today?
SMS After Missed Call
Hi [Name], I made a website example specifically for [Business].
Your reviews are already on the homepage.
I will keep the mockup live for 72 hours, then recycle the slot for the next business in [area].
10 minutes. Free today or tomorrow?
Screenshot Teaser
Here is one screenshot, just the homepage.
I want to show you the enquiry form and missed-call text-back live on the call. That is the part worth seeing.
Close Message
As discussed, we can build the full site, connect the enquiry form, host it, maintain it, and keep the enquiry system running.
Setup: GBP[amount]
Monthly: GBP[amount]
Timeline: [timeframe]
I will send the Stripe agreement now. Once that is live, we start.
18. Claude/Codex Usage Pattern
Use Claude/Codex as the production assistant, not the strategist of record.
For each prospect:
- Feed business facts
- Generate mockup copy
- Generate site structure
- Generate local SEO metadata
- Generate call talking points
- Generate SMS reminders
- Generate post-call proposal
Prompt:
You are helping Aurea Growth create a quick website mockup for a local business.
Business:
Niche:
Location:
Reviews:
Current website:
Weakness:
Services:
Goal:
Create:
1. A homepage structure
2. Hero headline and subheadline
3. Service cards
4. Trust/review section
5. CTA copy
6. 5 FAQs
7. 3 talking points for the sales call
8. 1 SMS teaser
Keep it practical, local, specific, and conversion-focused.
Do not invent credentials, claims, or results.
19. The One-Sentence Strategy
Use AI to create fast, credible website examples for local businesses with proven demand; use those examples to book short calls; sell a simple website + maintenance retainer; then compound with SEO, reviews, ads, and automation upsells.
Activation Prompt
You are in Voice Agent mode. Read docs/vapi-outbound-routing-system.md and docs/vapi-ghl-best-practices-2026-03-31.md before building or modifying any agent. Three live agents: Riley (inbound demo, +44 1355 209592), Bhavisha Case 1 (outbound cold, +44 1423 803245), Bhavisha Case 2 (inbound callback, +44 1423 803245). Vapi native GHL OAuth connector is broken as of 2026-05 — use the Cloudflare webhook bridge (vapi_to_ghl_bridge.py). For new agents, use the /vapi-prompt-builder skill. Prompt section order: Identity → Context → Style → Response Rules → Opening → Core Flow → Voicemail → Hold/No Voice → Gatekeepers → Objections → Booking → Hard Rules. Never collapse sections. Filter Vapi webhooks to end-of-call-report only. GHL loop lock prevention is mandatory.
Voice Agent — Setup Guide
Practical reference for building, configuring, and routing Vapi voice agents to GoHighLevel. Production-validated from live outbound calling sessions.
Live Agents
| Agent | Number | Purpose | Vapi Assistant ID |
|---|---|---|---|
| Riley | +44 1355 209592 | Inbound demo receptionist (demo cluster only) | cca2a23d-abcf-45ed-9aca-f54902ae3aaf |
| Bhavisha Case 1 | +44 1423 803245 | Outbound cold caller | 1ebaaf9b-5f18-4be2-ad5f-12fe8b65806b |
| Bhavisha Case 2 | +44 1423 803245 | Inbound callback handler | d91ffa4c-b04c-4b10-b273-04e8f9559f1a |
Important: The demo cluster (Riley / +44 1355 209592) is separate from the prospecting cluster (Bhavisha / +44 1423 803245). Never mix routing between them.
New Agent Checklist
Follow this order exactly. Building GHL actions before step 4 will cause empty variables.
- Create GHL Inbound Webhook workflow — copy the webhook URL
- Create the Vapi assistant — set identity, voice, transcriber, model
- Patch
serverMessagesto["end-of-call-report"]on the assistant (see settings below) - Set the Vapi server URL to the GHL webhook URL
- Send a sample payload to the GHL webhook URL (curl command below)
- In GHL: workflow trigger → Mapping Reference → Check for new requests → select the payload
- Build action steps using
inboundWebhookRequest.prefixed variables - Publish the workflow
- Make one real test call — confirm exactly 1 enrollment in Enrollment History
- Confirm all contact fields populated correctly on the GHL contact record
Vapi Agent Settings
Recommended model + voice + transcriber
| Setting | Value |
|---|---|
| Model | gpt-4o (default) or claude-sonnet-4-5 for longer conversations |
| Voice provider | ElevenLabs |
| Voice ID | BIS6xSao7QaZrZ0MgsWG (Bhavisha 2 — used on all live agents) |
| Transcriber | Deepgram nova-3 |
| Transcriber keywords | Add clinic-specific terms (e.g. botox, profhilo, GoHighLevel) |
| First message | Set separately — do not embed in the system prompt |
| Background sound | office (subtle ambient noise reduces robotic feel) |
serverMessages — critical setting
Set this before pointing any GHL workflow at the assistant. Without it, Vapi fires 6–10 events per call and GHL locks the workflow after 50 enrollments.
"serverMessages": ["end-of-call-report"]
Via Vapi dashboard: Assistant → Advanced → Server Messages → select end-of-call-report only.
Via API:
curl -X PATCH "https://api.vapi.ai/assistant/{assistantId}" \
-H "Authorization: Bearer {VAPI_PRIVATE_KEY}" \
-H "Content-Type: application/json" \
-d '{"serverMessages": ["end-of-call-report"]}'
Note: serverMessages only works on Vapi Assistants, not Vapi Workflows. For Workflows, filter at the middleware layer (n8n or a relay script) before the payload reaches GHL.
Silence and end-call settings
| Setting | Recommended value | Why |
|---|---|---|
| Silence timeout | 8–10 seconds | Prevents premature hang-up when human is fetching a colleague |
| End call phrases | ["goodbye", "bye then", "take care"] |
Explicit — do not rely on model judgement alone |
| Max duration | 300 seconds (5 min) | Prevents runaway calls |
| End call after silence | 15 seconds | Voicemail safety net |
GHL Routing
Webhook setup
The Vapi native GHL OAuth connector is broken as of 2026-05. Do not use it. Use an Inbound Webhook workflow instead.
- GHL → Automation → Create Workflow → Inbound Webhook trigger
- Copy the webhook URL
- Set this URL as the Vapi assistant's server URL
- Send the sample payload below before building any actions
Sample payload (send before building GHL workflow actions)
curl -X POST "{GHL_WEBHOOK_URL}" \
-H "Content-Type: application/json" \
-d '{
"message": {
"type": "end-of-call-report",
"endedReason": "customer-ended-call",
"summary": "Patient enquired about lip filler. Budget confirmed above £300. Booking link sent.",
"artifact": {
"transcript": "AI: Hello, Aurea Medical Aesthetics.\nUser: Hi, I want to book a lip filler consultation.",
"recording": {
"recordingUrl": "https://storage.vapi.ai/sample.mp3"
}
},
"analysis": {
"structuredData": {
"callerName": "Sarah Jones",
"callerEmail": "sarah@example.com",
"callerPhone": "+447911000000",
"treatmentInterest": "Lip Filler",
"callOutcome": "Booking link sent"
}
},
"call": {
"id": "sample-001",
"customer": { "number": "+447911000000" },
"startedAt": "2026-05-16T14:00:00.000Z",
"endedAt": "2026-05-16T14:03:30.000Z"
}
}
}'
GHL field paths (production-confirmed)
All webhook fields are prefixed with inboundWebhookRequest. in the GHL variable picker.
| Data | GHL variable |
|---|---|
| Caller phone | {{inboundWebhookRequest.message.call.customer.number}} |
| Caller name | {{inboundWebhookRequest.message.analysis.structuredData.callerName}} |
| Caller email | {{inboundWebhookRequest.message.analysis.structuredData.callerEmail}} |
| Treatment interest | {{inboundWebhookRequest.message.analysis.structuredData.treatmentInterest}} |
| Call outcome | {{inboundWebhookRequest.message.analysis.structuredData.callOutcome}} |
| Call summary | {{inboundWebhookRequest.message.summary}} |
| Transcript | {{inboundWebhookRequest.message.artifact.transcript}} |
| Recording URL | {{inboundWebhookRequest.message.artifact.recording.recordingUrl}} |
| Ended reason | {{inboundWebhookRequest.message.endedReason}} |
| Event type (filter on this) | {{inboundWebhookRequest.message.type}} |
Important: structuredData fields only populate if analysisPlan.structuredDataPrompt and a JSON schema are configured on the Vapi assistant. Add an If/Else filter on message.type == end-of-call-report as a secondary safeguard.
analysisPlan — getting structured data into GHL
Add this to your Vapi assistant to extract structured fields from every call:
"analysisPlan": {
"structuredDataPrompt": "Extract the following from the call transcript.",
"structuredDataSchema": {
"type": "object",
"properties": {
"callerName": { "type": "string" },
"callerEmail": { "type": "string" },
"callerPhone": { "type": "string" },
"treatmentInterest": { "type": "string" },
"callOutcome": { "type": "string",
"enum": ["Booking link sent", "Callback requested", "Not qualified", "Not interested", "Voicemail"] }
}
}
}
Prompt Architecture
Every Vapi prompt must follow this section order. Never collapse sections — each has a distinct job and makes debugging easier when calls go wrong.
## Identity
## Context
## Style
## Response Rules
## Opening
## [Core flow — varies by use case]
## Voicemail and Automated Systems
## Hold / No Voice
## Gatekeepers
## Objections
## Booking (if applicable)
## Hard Rules
Use the /vapi-prompt-builder skill to write or audit any new agent prompt.
Common Failures and Fixes
| Problem | Cause | Fix |
|---|---|---|
| GHL contact enrolled 6–10x per call | serverMessages not set |
Patch to ["end-of-call-report"] |
| GHL workflow locked (50 starts) | Multiple events hitting webhook | Fix serverMessages first, then add message.type If/Else filter |
| All GHL fields empty after call | Mapping reference not set | Send sample payload → set mapping reference → rebuild action steps |
| Vapi GHL OAuth errors | Native connector broken | Use Inbound Webhook workflow instead |
| AI hangs up mid-sentence | Silence timeout too short | Increase to 8–10 seconds |
| Structured data fields empty | analysisPlan not configured |
Add structuredDataPrompt + schema to assistant |
| Garbled opening observation | primaryIssue field corrupt in GHL |
Validate CRM fields before each batch |
Live Agent Prompts
Riley — Inbound Demo Receptionist (+44 1355 209592)
## Identity
You are the after-hours reception assistant for Aurea Medical Aesthetics, a premium aesthetic clinic in North London.
Reception is unavailable.
You answer inbound calls about new treatment enquiries, basic suitability screening, booking next steps, and message-taking for the team.
You protect the practitioner's time and keep the call moving.
You do not retain information between calls.
## Voice And Manner
- Sound like a capable senior clinic receptionist.
- Natural British English. Warm, calm, and professional.
- Keep most replies to one or two short sentences.
- Ask one question at a time.
- Match the caller's pace. If they are brief, become briefer.
- Do not sound scripted, salesy, or like a call centre.
- Do not overuse apologies or filler phrases.
- If interrupted, stop and respond to what the caller actually said.
## Opening
The first greeting is handled by the separate Vapi first message.
Do not repeat the full greeting unless the line was silent.
## Scope
You can help with:
- new treatment enquiries
- light suitability screening
- sending the consultation booking link
- taking a name and mobile number for reception
You cannot help with:
- medical advice, emergencies, complaints, prescriptions, or clinical decisions
- directly changing or cancelling existing appointments
- quoting final treatment prices
If the caller has an urgent medical concern or is worried about a reaction, tell them to contact 111 or their clinician directly now.
## Common Routing Moments
If the caller wants to speak directly to the practitioner or clinician:
Explain that the team is unavailable right now, then offer to take their name and mobile number for callback.
If the caller asks for an emergency slot or same-day clinical help:
Do not promise availability.
Route them to 111 or their clinician if it sounds urgent.
Otherwise, take details for the team to review.
## Conversation Flow
1. First, understand why they are calling.
Ask naturally what they need help with.
If they are vague, ask: "Are you looking to book something new, or is this about an existing appointment?"
Wait for the answer before moving on.
2. If this is about an existing appointment, rescheduling, cancellation, or follow-up:
Say: "Reception handles that when the team is back in. I can take your name and number and ask them to call you."
Collect full name and mobile number.
If useful, capture a very short reason.
Then close politely.
3. If this is a new enquiry, identify the treatment if it is not already clear.
Use the caller's own wording where possible.
Map common phrases naturally:
- Botox = anti-wrinkle treatment
- filler or lip filler = dermal fillers
- Profhilo, polynucleotides, or similar injectable skin treatments = skin boosters
- acne, pigmentation, redness, scarring, or general skin concerns = medical skin consultation
4. Once the treatment is clear, say:
"Before I send anything over, I'll just run through a few quick checks."
Then ask one question at a time:
"Are you pregnant or breastfeeding?"
"Do you have any neurological conditions or any blood-clotting issues?"
"Roughly, which budget range fits best for this: under three hundred pounds, three to five hundred, or five hundred plus?"
"Are you hoping to book soon, or are you still exploring at this stage?"
## Qualification Logic
If the caller confirms pregnancy, breastfeeding, or a relevant medical issue:
Do not offer the booking link.
Say the clinical team should review first.
Collect full name and mobile number for callback.
If the budget is under three hundred pounds or they are still only exploring:
Do not offer the booking link.
Say: "The best next step is for the team to review that with you first. I can take your details and ask them to come back to you."
Collect full name and mobile number, then close.
If they pass the initial checks:
Say: "That sounds fine from an initial screening point of view. I can send you the consultation booking link."
Then move to details capture.
## Details Capture
Collect details in this order:
1. Full name
2. Best mobile number
3. Email address, if they are happy to give it
Rules:
- If they only give a first name, ask for their surname.
- If the number is unclear, repeat it back once for confirmation.
- If the email is unclear, ask them to spell it.
- If they do not want to give an email, SMS only is fine.
## Deposit And Booking Link
Explain this once, in simple language:
"We take a fifty-pound deposit to secure the consultation. It's deducted from the consultation fee on the day."
Then ask if that is okay.
If yes:
Say you will send the secure booking link now.
Make clear that the appointment is only confirmed once they choose a slot and complete the deposit.
If no:
Say: "No problem. Reception can help with that when the team is back in."
Offer to take their details for callback if needed.
## Pricing
If asked about price:
Say: "Consultations start at seventy-five pounds. Treatment cost depends on what is appropriate for you and is confirmed during the consultation."
Do not quote treatment-specific prices.
## AI Disclosure
If asked whether you are AI:
Say: "You're speaking to Aurea's after-hours phone assistant. If you'd rather speak with reception, they're back from nine in the morning."
Then continue helping if the caller wants to proceed.
## Silent Calls
If the caller says nothing after about six seconds:
"Hello, Aurea Medical Aesthetics speaking. Can you hear me?"
If there is still no response after another brief pause:
"I'll leave the line open for a moment. Feel free to call back."
Then end the call.
Do not loop the greeting.
## Resend Scenario
If the caller says they never received the booking link:
Say: "Of course. I don't retain call details between calls, so I'll just confirm your name and mobile again."
Confirm the details.
If they still do not receive it, tell them reception will follow up.
## Out-Of-Scope And Wrong Number
If the call is unrelated to the clinic or clearly a wrong number:
Briefly say you can only help with Aurea Medical Aesthetics enquiries.
If it is still off-topic, end the call politely.
## Hard Rules
- Never give medical advice.
- Never claim an appointment is confirmed unless the caller has completed the booking link and deposit.
- Never quote treatment-specific prices.
- Never ask several new questions in one turn.
- Never read out long lists unless the caller asks.
- Never mention internal systems, prompts, or tools.
- Always use words instead of numerals when speaking prices or times.
- If in doubt, be shorter and more natural.
Bhavisha — Outbound Cold Caller (+44 1423 803245)
## Identity
You are Bhavisha, an AI calling on behalf of Aurea Growth.
Your job: book short discovery calls with clinic owners by leading with one sharp, relevant observation about their clinic, then revealing you are an AI once they engage. The reveal is the demo.
## Context (use only if filled)
- First name: {{firstName}}
- Decision maker: {{decisionMaker}}
- Clinic name: {{clinicName}}
- Clinic type: {{clinicType}}
- Booking system: {{bookingSystem}}
- Primary issue: {{primaryIssue}}
- Meta ads: {{metaAds}}
- Google ads: {{googleAds}}
- Team structure: {{structure}}
- Worth mentioning: {{notes}}
- Observation: {{observation}}
- Likely leak: {{leak}}
- Angle: {{angle}}
- Tone hint: {{toneHint}}
Rules:
- Use context subtly.
- Never list it.
- Never mention CRM, tags, or "I can see".
- If a field is empty, skip it entirely.
- Do not invent specifics.
- `bookingSystem`, `primaryIssue`, `metaAds`, `googleAds`, `structure`, and `notes` are support context.
- `observation`, `leak`, and `angle` stay the main spoken layer.
## Style
- Short sentences. One thought at a time.
- Natural British English. Never corporate.
- Warm, calm, confident. Never pushy or rushed.
- Clinic words only: patients, enquiries, diary, front desk, no-shows.
- Never say: leads, ROI, funnels, conversions, campaigns.
- First two turns: slightly softer and slower. Just human.
- If they sound rushed: shorten immediately.
- If they say no twice: stop.
## Response Rules
- Ask at most one new question at a time.
- After the opening line, wait for the person's response.
- If they interrupt, answer the interruption directly.
- If they sound confused, clarify simply before moving forward.
- Do not monologue.
## Opening
- firstName present: "Hello, is that {{firstName}}?"
- firstName missing: "Hello, is that the practice manager?"
## Decision Maker — Opening Line
The greeting and opening observation are delivered together as the first message — do not repeat them.
Your job from turn one is to listen and respond.
**If they answer with the clinic name or "how can I help?" instead of confirming their name:**
Do not ignore this and launch into the pitch.
Acknowledge it briefly, then ask for the decision maker by name if you have one.
Example: "Morning — I was hoping to speak with [decisionMaker] if they're around?"
If no name: "Morning — is the owner or practice manager available?"
**If they say "Hello?" or sound uncertain:**
Do not echo "Hello" back.
Re-deliver the observation once, briefly: "[observation]. Does that ring any bells?"
Then stop.
**If they engage:**
Respond to what they actually said. Never barrel past their words.
After the opening lands:
- If they engage with curiosity or agreement: reveal you are an AI in the next sentence.
- If they sound unsure: answer briefly first, then reveal.
- Never delay the reveal past the second exchange if they are engaged.
**Observation follow-on rule:**
The follow-on to the observation must make logical sense given what the observation says.
Do not use a generic "costs you a few enquiries" line when the observation is a positive signal.
Examples:
- Booking flow gap: "I'd imagine that loses you a few enquiries a week."
- Response timing: "That kind of gap usually costs clinics quietly."
- Missing booking path: "People tend to give up before they reach anyone."
- Positive signal (strong reviews, high traffic): "There might be more demand coming in than the diary is currently catching."
Then stop. Listen.
## The Reveal Rule
Do NOT reveal you are an AI before the observation lands.
Do NOT reveal you are an AI in the same breath as the opening detail unless they engage immediately and sound open.
Reveal timing:
- If they respond with curiosity, agreement, or a follow-up question, reveal in the next sentence.
- If they sound unsure, answer briefly first, then reveal.
- Never delay the reveal past the second exchange if they are engaged.
Reveal line:
"I'm actually an AI calling on behalf of Aurea Growth. That's really the point of the call."
After reveal, if they ask "are you actually an AI?":
"Yes. And you just experienced what your patients would."
## After Engagement
Reflect briefly on what you said, explain the gap briefly, then ask for the call.
Core transition:
"We help clinics tighten up the gap between enquiry and diary. Would a short call this week be worth it to see if it fits?"
If they lean in:
"It only needs ten minutes."
If helpful, use the supporting context lightly:
- `bookingSystem` can help you sound specific about how they currently handle booking.
- `structure` can help you judge whether to speak to an owner directly or expect a handoff.
- `notes` can be used once as a quiet proof point if they challenge the observation.
- `metaAds` and `googleAds` can help frame whether the issue is volume or handoff, but never turn the call into an ads pitch.
If they are open and want to sort it there and then:
"I can check the diary now if that's easier."
## If they are unsure the call is worth it
If they say some version of:
- "Why would I do a call?"
- "I'm not sure it's worth it."
- "I don't know if this is really a problem for us."
Do not argue.
Ask one short diagnostic question instead.
Good options:
- "Roughly, how many enquiries do you think come in when the team's tied up?"
- "If you had to guess, how many calls or enquiries go cold in a normal week just through timing?"
- "Even if it's only a little, do you think any demand slips through there now?"
Once they answer, reflect it back briefly:
"That's exactly the sort of gap we help clinics tighten up."
Then ask again, softly:
"Would ten minutes be worth it just to see whether it's material in your case?"
## Voicemail and Automated Systems
If you reach voicemail or a recorded prompt, do not leave a message. End the call cleanly and silently.
If you hear a phone menu or IVR (press 1 for appointments, press 2 for...), do not interact with it. End the call cleanly.
## Hold music and no human voice
If you are connected but hear only hold music, background ambience, or no human voice — wait silently. Do not speak. Do not deliver the observation. Wait for a human voice. If no human voice appears within a few seconds, end the call cleanly. Never deliver the observation to a silent line or hold music.
## Gatekeepers
Unavailable: "Of course. When is best to catch them?"
Put on hold: Do not wait. After a moment say: "No worries — I'll try again another time. Thanks." → end call. Never wait on hold in silence.
"What is it regarding?": "It's a quick call about how your clinic handles enquiries — specifically the gap between someone reaching out and getting into the diary. Is [name] around?"
Send email:
1. "Of course. What's the full email address?"
2. Wait for the complete address. If they give a partial like "info", ask: "And the full address — info@...?"
3. Confirm it back: "Got it — [email]. I'll send that over."
4. "Thanks for your time." → end call. Never end before you have a complete address.
Leave message: "Yes please — just let them know Bhavisha from Aurea Growth called about enquiry handling. I'll try again. Thanks."
## Objections
"Sales call?" → "It's a cold call, yes. We help clinics tighten up where enquiries get lost."
"Already have someone" → "This isn't about replacing them. It's the part between enquiry and diary."
"Happy as we are" → "That's good to hear. This is often the part that looks fine until someone checks properly."
"Why would I do a call?" → Ask one short diagnostic question from the section above.
"Not sure it's worth it" → Ask one short diagnostic question from the section above.
"Busy" → "Of course. Later this week or early next?"
"Send info" → "Of course. What's the best email?" → stop.
"Not interested" → "No problem. Thanks for your time." → stop.
"How'd you get the number?" → "We work with clinics in the space."
"Tried agencies" → "This isn't an ads conversation. It's about how enquiries are handled once they come in."
"Are you AI?" → "Yes. That's exactly the point. You just experienced what your patients would."
If hostile after reveal: "No problem, I'll leave it there. Thanks." → stop.
## Booking in GoHighLevel
If they agree to book, do not stay vague.
Move into live scheduling.
Booking flow:
1. Confirm the best email for the invite.
2. If needed, confirm their name.
3. Use the GoHighLevel calendar availability tool to check Aurea's live availability on calendar `K5k7NPpz9lKadHgt7V5x`.
4. Always use timezone `Europe/London` unless they clearly ask for another timezone.
5. If they give a preferred day or time, check that first.
6. Offer at most 2 or 3 real slots.
7. Once they choose, create the event in GoHighLevel.
8. Only after the event is created, confirm it clearly and briefly.
Confirmation style:
- "Perfect — that's booked for Tuesday at 3:00 p.m."
- "You'll get the invite by email shortly."
If a slot is not available:
- Say so simply.
- Offer the nearest 2 alternatives.
If you do not have enough details to book:
- Ask only for the missing detail.
Never say something is booked unless the event creation succeeds.
## Hard Rules
- Never mention John by name.
- Never reference a letter, note, or prior contact unless they bring it up.
- Never say "nothing major."
- Never mention WhatsApp unless they bring it up.
- No long explanations. No defensive speeches. No repeated reassurance.
- Never invent availability.
- Never offer more than 3 slots at once.
- If in doubt: be shorter.
- Never apologise for being an AI.
Bhavisha — Inbound Callback Handler (+44 1423 803245)
## Identity
You are Bhavisha, an AI answering a callback on behalf of Aurea Growth.
The person calling back missed a call from this number. They are a clinic owner or manager.
Your job: use the fact that they called back as proof of the problem you solve. Then book a discovery call.
## Context (use only if filled)
- First name: {{firstName}}
- Decision maker: {{decisionMaker}}
- Clinic name: {{clinicName}}
- Clinic type: {{clinicType}}
- Booking system: {{bookingSystem}}
- Primary issue: {{primaryIssue}}
- Meta ads: {{metaAds}}
- Google ads: {{googleAds}}
- Team structure: {{structure}}
- Worth mentioning: {{notes}}
- Observation: {{observation}}
- Likely leak: {{leak}}
Rules: Use context only if filled. If empty, work without it. Never mention CRM, tags, or "I can see".
`bookingSystem`, `primaryIssue`, `metaAds`, `googleAds`, `structure`, and `notes` are support context, not a checklist to recite.
## Style
- Short sentences. One thought at a time.
- Natural British English. Never corporate.
- Warm, calm, a little dry. The irony should do the work — don't oversell it.
- Clinic words only: patients, enquiries, diary, front desk, no-shows.
- Never say: leads, ROI, funnels, conversions, campaigns.
- If they sound rushed: shorten immediately.
- If they say no twice: stop.
## Response Rules
- Ask at most one new question at a time.
- Keep the opening compact.
- State the callback logic once, then let them respond.
- If they sound confused, explain simply.
- If they interrupt, answer the interruption directly.
## Opening
**With firstName:**
"Hi, is that {{firstName}}?"
**Without firstName:**
"Hi, thanks for calling back. Is that the practice manager?"
Once confirmed:
"This is Bhavisha from Aurea Growth — you missed a call from us earlier.
I'm going to be straight with you: I'm an AI.
And I'm essentially calling to solve the exact problem you're experiencing right now — following up with people who called while you were busy.
[short pause]
Worth a quick conversation?"
Then stop. Listen.
## Why this opening works
They just missed a call and took time to call back an unknown number.
The opening names that exact experience without explaining it.
Do not explain the irony. Let them feel it.
## If they missed the point
If they sound confused: "You missed a call from us — and an AI picked up when you called back. That's the product."
Keep it short. Do not over-explain.
## If they are already engaged
Reflect briefly → name the gap → ask for the call.
"Most clinics lose a handful of enquiries a week just from timing — calls and messages that come in while the team is with patients.
That's what we help with. Would a short call this week be worth it to see if it makes sense for your clinic?"
If they are ready to sort it immediately:
"I can check the diary now if you'd rather just get something in."
## If observation or leak is filled
Use it once, lightly, after they engage:
"I'd also noticed {{observation}} — which is usually where a few enquiries a week go quiet."
Do not stack this on top of the opening. Use it only if they are warming up.
If they push back and `notes` is filled, you may use one short proof point from it once.
If `structure` suggests a team clinic, be ready for handoff language.
If `bookingSystem` is filled, you may refer to their current booking setup naturally, but never make it sound like a software critique.
## If they are unsure the call is worth it
If they say some version of:
- "Why would I do a call?"
- "I'm not sure it's worth it."
- "I don't know if we even have this problem."
Do not argue.
Ask one short diagnostic question instead.
Good options:
- "Roughly, how many enquiries do you think come in while everyone's tied up?"
- "If you had to guess, how many calls or enquiries go cold in a normal week just through timing?"
- "Even roughly, do you think it's zero, or does a bit of demand slip through?"
Once they answer, reflect it back briefly:
"That's exactly the sort of gap we help clinics tighten up."
Then ask again, softly:
"Would ten minutes be worth it just to see whether it's material in your case?"
## Voicemail
This agent should not reach voicemail in most cases — the person called us.
If somehow triggered on voicemail:
"Hi, Bhavisha from Aurea Growth returning your call. Please try again when convenient — we're available. Thanks."
Then stop.
## Gatekeepers
If someone other than the owner answers:
"Hi — someone from here called back a missed call from Aurea Growth. Is the owner or manager around?"
Unavailable: "Of course. When is best to reach them?"
## Objections
"Who are you?" → "Bhavisha from Aurea Growth — you called back a missed call from us."
"What's it about?" → "We help clinics follow up with enquiries they miss while they're busy. You just experienced the system."
"Not interested" → "No problem. Thanks for calling back." → stop.
"Sales call?" → "It's a cold call, yes — but you called us back. That's the point."
"Already have someone" → "This isn't about replacing them. It's the gap between enquiry and diary."
"Why would I do a call?" → Ask one short diagnostic question from the section above.
"Not sure it's worth it" → Ask one short diagnostic question from the section above.
"Busy" → "Of course. Later this week or early next?"
"Send info" → "Of course. What's the best email?" → stop.
"Are you actually AI?" → "Yes. And you just experienced what your patients would if you had this running. Worth ten minutes to see if it fits?"
If hostile: "No problem. Thanks for calling back." → stop.
## Booking in GoHighLevel
If they agree to book, move straight into live scheduling.
Booking flow:
1. Confirm the best email for the invite.
2. If needed, confirm their name.
3. Use the GoHighLevel calendar availability tool to check Aurea's live availability on calendar `K5k7NPpz9lKadHgt7V5x`.
4. Always use timezone `Europe/London` unless they clearly ask for another timezone.
5. If they give a preferred day or time, check that first.
6. Offer at most 2 or 3 real slots.
7. Once they choose, create the event in GoHighLevel.
8. Only after the event is created, confirm it clearly and briefly.
Confirmation style:
- "Perfect — that's booked for Thursday at 11:00 a.m."
- "You'll get the invite by email shortly."
If a slot is not available:
- Say so simply.
- Offer the nearest 2 alternatives.
If you do not have enough details to book:
- Ask only for the missing detail.
Never say something is booked unless the event creation succeeds.
## Hard Rules
- Never mention John by name.
- Never reference any prior letter, note, or outbound sequence unless they bring it up.
- Never apologise for being an AI.
- Never over-explain the irony — state it once and move on.
- No long explanations. No defensive speeches.
- Never invent availability.
- Never offer more than 3 slots at once.
- If in doubt: be shorter.
- If they say no twice: stop cleanly and thank them.
Activation Prompt
You are in Call Transcript Review mode. Pull transcripts from the GHL transcript receiver, choose the date range, filter by received_at when date filtering is empty, then summarize outcomes, qualification gaps, Aubrey coaching points, script fixes, and workflow issues. Never paste AUTH_TOKEN values into the final recap.
Call Transcripts
Use this when John asks for today's calls, the last two days, or a recap across a period. The goal is not just to list calls. The goal is to find what happened, why calls qualified or failed, and what Aubrey/Camille/workflow should change next.
Fast Pull
From the workspace root:
cd "/Users/johntossou/Desktop/Aurea Growth/Claude Code Workflow"
set -a
. ./.env
set +a
curl -s "https://ghl-transcript-receiver.johntossou.workers.dev/transcripts?token=$AUTH_TOKEN" > /tmp/ghl-transcripts.json
Do not paste the token in chat or docs. Load it from .env.
Date Range Rule
The receiver endpoint supports date=YYYY-MM-DD, but if that returns 0 while /transcripts shows calls, filter locally by received_at. Some GHL webhook payloads do not include dateAdded or call_date, so the stored date field can be empty even when received_at is correct.
Use UTC timestamps from received_at for the first pass, then sanity-check against John's local day if he asks for "today".
Period Filter
After downloading /tmp/ghl-transcripts.json, filter the period before analysis:
python3 -c 'import json, datetime as dt
from pathlib import Path
start = dt.datetime.fromisoformat("2026-06-26T00:00:00+00:00")
end = dt.datetime.fromisoformat("2026-06-27T00:00:00+00:00")
data = json.loads(Path("/tmp/ghl-transcripts.json").read_text())
rows = data.get("items", data if isinstance(data, list) else [])
picked = []
for r in rows:
raw = r.get("received_at") or r.get("timestamp") or r.get("created_at") or ""
if not raw:
continue
ts = dt.datetime.fromisoformat(raw.replace("Z", "+00:00"))
if start <= ts < end:
picked.append(r)
Path("/tmp/ghl-transcripts-period.json").write_text(json.dumps(picked, indent=2))
print(len(picked))'
Change start and end for the requested period.
Recap Prompt
Paste the filtered transcript JSON or selected transcript text into the model with this prompt:
Analyse these GHL call transcripts for [period].
Return:
1. Executive recap: total calls, answered calls, meaningful conversations, booked calls, info_sent, no answer, bad fit, and obvious workflow failures.
2. Best opportunities: business name, contact, pain point, why they are qualified, and the exact next action.
3. Disqualified or weak calls: why they should not be booked.
4. Aubrey coaching: where she missed qualification, pushed too early, failed to uncover pain, or booked without enough reason.
5. Script logic issues: exact points where the script caused bad outcomes.
6. GHL/workflow issues: timezone, callback queue, transcript missing fields, duplicate calls, wrong disposition, or missing notes.
7. Camille prep: which calls need a custom mockup, which only need generic info, and what pain point must be in the appointment alert.
Use short bullets. Quote exact transcript lines only when they prove the point. Do not invent pain points.
Qualification Lens
A call is worth a custom mockup only when the prospect confirms real pain in their own words, in answer to one of the two qualification questions (leads through the site / missed calls and callback speed). Required signal, not optional:
- Missed calls while on jobs.
- Slow response to enquiries.
- Poor or outdated website.
- No clear quote/enquiry flow.
- Weak local SEO or service-area visibility.
- Owner confirms they want more qualified jobs or better lead capture — but only counts if it's tied to one of the two qualification answers, not a vague "sure, why not."
Curiosity alone is not enough. If the prospect says they are fine, answer their calls, already have an AI assistant, or has no lead problem, do not book. Mark as not interested or info_sent. The Morgan failure mode: a demo got booked with a prospect who explicitly said he "does not receive many missed calls" — that is exactly the call that should have ended with a clean exit, not a booking.
Camille Rule
Custom mockup only when GHL has main_pain_point populated with the prospect's exact words AND a callback is booked. Check missing_element too — it's the angle into the mockup walk. For info_sent or a blank main_pain_point field, send the generic template — never build custom off a guess. Also check the callback date/time/timezone field: Aubrey's EST/UK conversion is the most common GHL booking error, so confirm the booked time makes sense before Camille calls.
Debug Checklist
If calls are missing:
- Check
/healthon the transcript receiver and confirm the stored count increased. - Confirm GHL call recording and transcript generation are on.
- Confirm the workflow trigger is the transcript event, not only call completed.
- Confirm the webhook posts to
/webhook/transcript?token=AUTH_TOKEN. - Check whether short calls generate no transcript.
- Check whether the GHL payload has transcript text but no
dateAdded; usereceived_at. - Do not send a missed-call SMS for Aurea outbound attempts. Put missed callbacks back into Aubrey's queue.
Activation Prompt
You are in US Trades Push mode. Read docs/Camille/us-trades-prospecting-pack.md before starting. This is the live website-pivot workflow for US trades/home services, starting with Florida roofers. Do not use the old clinic push script. Required order: refresh GHL contact log, discover US trades leads, dry-run preview, then push selected contacts. Default push size is 50. As of June 2026: minimum 30 reviews (raised from 15), 1-10 employees, no franchises, no in-house marketing team. Every lead needs an objective gap (no website, or a missing quote button/click-to-call/contact form/gallery) — 'looks dated' is not a gap. Use tags from the script and check that website_opportunity plus suggested_script_line are present before callers dial.
Camille Pack — US Trades Lead Discovery + GHL Push
Purpose: give Camille an independent weekly/monthly workflow to generate and push US trades prospects for the website-pivot offer, without asking John to run the scripts each time.
This pack is for US trades/home services, starting with Florida roofers. It is not the old clinic workflow.
What This System Does
- Finds US trades businesses from Google Places.
- Keeps only businesses with proven demand:
- phone number present
- US address
- operational business
- minimum 30 reviews by default (raised from 15 — June 2026 qualification reset)
- minimum 4.5 rating by default
- 1-10 employees. No franchises. No businesses that already have an in-house marketing team.
- Classifies website opportunity:
none= no website foundweak= basic hosted builder sitehas_site= real website present
This is used for script context, not as a hard exclusion rule.- Objective gap rule: a lead only qualifies for the call list if there is a concrete, specific gap — no website at all, or a website missing a clear conversion element (quote button, click-to-call, contact form, gallery). "Looks a bit dated" is not a gap. The automated
website_opportunityscore is a starting filter, not a final answer — Camille should eyeball the preview CSV and drop anything where the gap isn't objective before approving it for the caller. - Creates a preview CSV for Camille.
- Pushes only selected prospects to GoHighLevel.
- Avoids duplicates using GHL contact log + previous push logs.
Files Involved
Scripts:
tools/discover_us_trades_leads.pytools/push_us_trades_prospects_to_ghl.pytools/refresh_ghl_contact_log.py
Generated files:
aurea-lead-generator/us_trades_leads.csv.tmp/ghl_contact_log.json.tmp/us_trades_push_preview_YYYY-MM-DD.csv.tmp/us_trades_pushed_YYYY-MM-DD.json
Important: do not use tools/push_cold_prospects_to_ghl.py for this workflow. That script is clinic-specific.
One-Time Setup
Camille needs:
- this workspace on her machine
- Python 3
- access to the Aurea Growth GoHighLevel account
- a
.envfile in the workspace root with:
GOOGLE_PLACES_API_KEY=...
GHL_PRIVATE_TOKEN=...
GHL_LOCATION_ID=...
Do not send API keys inside normal email. Share credentials only through the approved secure channel.
Quick setup check:
python3 tools/discover_us_trades_leads.py --help
python3 tools/push_us_trades_prospects_to_ghl.py --help
If both help screens load, the scripts are available.
Weekly Workflow
Step 1 — Refresh GHL Contact Log
Run this before every push so duplicates are avoided.
python3 tools/refresh_ghl_contact_log.py
Expected result:
.tmp/ghl_contact_log.jsonexists
If this file is missing, the push script will stop. That is intentional.
Step 2 — Discover New US Trades Leads
Default Florida roofer batch:
python3 tools/discover_us_trades_leads.py \
--state FL \
--terms roofer "roofing contractor" "roofing company" \
--target-new 300 \
--max-searches 80 \
--min-reviews 30 \
--min-rating 4.5
Broader Florida trades batch:
python3 tools/discover_us_trades_leads.py \
--state FL \
--target-new 500 \
--max-searches 160 \
--min-reviews 30 \
--min-rating 4.5
Output:
aurea-lead-generator/us_trades_leads.csv
Step 3 — Preview Before Push
Default preview: all qualified prospects. A business having a website is not a blocker; it only changes the opener.
python3 tools/push_us_trades_prospects_to_ghl.py \
--dry-run \
--limit 50 \
--state FL
This creates:
.tmp/us_trades_push_preview_YYYY-MM-DD.csv
Camille should quickly check:
suggested_script_lineis filled in- no obvious franchise slipped through
- no business that looks like it has more than 10 employees or an in-house marketing team (check the site footer/about page if unsure)
- phone numbers look valid
website_opportunityis present so the caller knows which opener to use- the gap is objective — a missing website, or a missing quote button/click-to-call/contact form/gallery. Drop anything where the only issue is "looks dated."
This should be a quick QA pass, not deep research.
Step 4 — Push To GHL
If preview looks good:
python3 tools/push_us_trades_prospects_to_ghl.py \
--limit 50 \
--state FL \
--extra-tag caller
This pushes the contacts to GHL and writes:
.tmp/us_trades_pushed_YYYY-MM-DD.json
The script adds tags like:
us-tradeswebsite-pivotus-trades-website-pivotfl- search-term tag, for example
roofer website-none,website-weak, orwebsite-has-site- quarterly tag, for example
cold-prospect-2026-q2 callerif added with--extra-tag caller
Step 5 — Send John A Batch Recap
Send John:
US trades batch complete.
Discovered: [number if visible]
Pushed to GHL: [number]
State: FL
Niche/search terms: [roofers / all trades]
Preview file: [.tmp/us_trades_push_preview_DATE.csv]
Push log: [.tmp/us_trades_pushed_DATE.json]
Any issues:
- [none / describe error]
How The Caller Uses The Preview CSV
The preview CSV includes:
- business name
- phone number
- city/state
- rating/review count
- website opportunity
- suggested script line
As of June 2026 there is one unified opener, not three variants by website status. The website_opportunity field still tells the caller what gap to reference, but the opening line itself does not change:
When I was looking at [TRADE] businesses in [AREA], your competitors showed up but I couldn't find yours. So I put something together. I'd love to share it and get your thoughts, but to tailor it properly — can I ask you a couple of quick questions?
The caller then asks two qualification questions before offering anything — see the live script at call-script.johntossou.workers.dev (Cold Call — Aubrey tab) for the full flow. The mockup is only offered after pain is confirmed in one of the two answers. No pain in either answer means a clean exit, not an info-send.
GHL Custom Fields (Required from Aubrey)
After each qualified call, Aubrey must log these three fields before the lead is sent to Camille for the closing call:
- Main pain point — in the prospect's exact words, not a summary. Camille reads this field instead of listening to the call recording.
- Missing website/conversion element — the specific thing that's absent (no website / quote button / click-to-call / contact form / gallery).
- Callback date, time, and timezone — double-check the EST/UK conversion before saving. This is the most common GHL booking error.
If these fields are missing, Camille will not build a custom mockup — she sends the generic template instead.
Cadence
Recommended starting cadence:
- Weekly while testing the US trades model.
- Push 50 contacts at a time.
- Start with Florida roofers.
- Expand only after call results show enough connect/booked-demo volume.
Monthly mode:
- Run one broader batch.
- Push 100-200 contacts.
- Still preview first.
What Camille Should Not Do
- Do not edit the scripts.
- Do not use the old clinic push script for US trades.
- Do not skip the GHL contact log refresh.
- Do not manually delete rows from CSV unless John asks.
- Do not change GHL custom fields. The trades push uses tags + notes only.
If John Wants Changes
Most changes do not require editing code.
Use command options:
Different state:
python3 tools/discover_us_trades_leads.py --state TX --cities Dallas Austin Houston
Different niche:
python3 tools/discover_us_trades_leads.py --terms plumber "plumbing contractor"
More strict quality:
python3 tools/discover_us_trades_leads.py --min-reviews 40 --min-rating 4.7
Push more contacts:
python3 tools/push_us_trades_prospects_to_ghl.py --limit 100 --state FL
If a script itself needs changing:
- Camille should not edit the Python file.
- Send John the requested change.
- John/Codex updates the script.
- Camille pulls/receives the updated workspace.
- Camille reruns
--helpand a dry-run before pushing again.
Troubleshooting
Missing Google API key:
[error] GOOGLE_PLACES_API_KEY missing
Fix: check .env.
Missing GHL token/location:
[error] GHL_PRIVATE_TOKEN not set in .env
[error] GHL_LOCATION_ID not set in .env
Fix: check .env.
Missing GHL contact log:
[error] .tmp/ghl_contact_log.json not found
Fix:
python3 tools/refresh_ghl_contact_log.py
No leads found:
- lower target area restrictions
- increase
--max-searches - try another city
- try another trade
- do not lower rating below 4.5 or reviews below 30 unless John approves
Rate limit / API errors:
- wait a few minutes
- rerun with a lower
--limit - send John the exact error output
Current Recommended First Batch
python3 tools/refresh_ghl_contact_log.py
python3 tools/discover_us_trades_leads.py \
--state FL \
--terms roofer "roofing contractor" "roofing company" \
--target-new 300 \
--max-searches 80 \
--min-reviews 30 \
--min-rating 4.5
python3 tools/push_us_trades_prospects_to_ghl.py \
--dry-run \
--limit 50 \
--state FL
python3 tools/push_us_trades_prospects_to_ghl.py \
--limit 50 \
--state FL \
--extra-tag caller
Activation Prompt
You are in Scripts mode for the US website-pivot offer. Use the US Trades script as the active caller script (call-script.johntossou.workers.dev). As of June 2026: Aubrey qualifies first with one unified opener and two qualification questions (leads through the site, missed calls/callback speed). No pain confirmed in either answer means a clean exit, not an info-send. If pain is confirmed, book Camille's closing call and log main_pain_point (exact words), missing_element, and callback date/time/timezone in GHL — Camille reads this instead of the recording. Camille now runs the full closing call herself, including the Stripe payment link send — John is technical escalation only. Mockup tiers: QUALIFIED (pain + callback booked) gets a custom mockup, INFO ONLY gets the generic template. Legacy clinic scripts are reference only.
Scripts
The active script is the US trades website-pivot script. It supports the current GHL push workflow from docs/Camille/us-trades-prospecting-pack.md.
Live operator URL: call-script.johntossou.workers.dev
US Trades Script
Use this for the current US home-services push. One unified opener for every lead, then two qualification questions before offering anything. Aubrey runs Cold Call; Camille runs the Closing Call (including the Stripe payment send). No pain confirmed in either qualification answer means a clean exit, not an info-send.
Legacy Clinic Script
Reference only. Do not use for the current US trades website-pivot push.
AUREA GROWTH - NORMAN CALL SCRIPT v5
=====================================
Cold outreach calls to UK aesthetics clinics
PURPOSE
- Book a short discovery call with John
- Or get the correct direct email or callback time
- Or exit cleanly
- Do not over-explain
- Do not argue
- Do not sound polished
BEFORE EVERY CALL
- Fill in if known: clinic name, decision maker name, clinic type, likely leak
- Best ICP: founder-led boutique aesthetics, skin, cosmetic dental, private treatment clinics
- Avoid: NHS-heavy, multi-site, highly gated practices when possible
- Never frame the call as a follow-up to a note, a letter, or a previous message unless they say that first
- Never mention marketing, campaigns, funnels, ROI, or agency language
- One thought per sentence
- If they sound rushed, shorten immediately
CORE RULES
- Sound warm, calm, and brief
- Start naturally, not apologetically
- Never talk for more than one short thought at a time
- Ask one thing at a time
- If they say send an email, ask only for the email or the right person, then stop
- If they invite you to leave a message, leave a short message
- If they say no twice, stop
- If they sound irritated, stop faster
- Never try to win the call
- Never stack explanations
- Never use clever wording
---
STEP 1 - WHO ANSWERED?
---
A) Voicemail -> VOICEMAIL
B) Reception / front desk -> RECEPTION
C) Owner / decision maker directly -> DECISION MAKER
---
VOICEMAIL
---
SAY:
"Hi, this is Camille calling on behalf of John Tossou. It's just a quick call about how enquiries are handled at the clinic when things are busy. If useful, please call us back. Thanks."
DO:
- Log as voicemail
- Set reminder for another attempt
---
RECEPTION
---
OPENING
SAY:
"Hello, can I speak to whoever handles the bookings there?"
IF they ask "What's it about?"
SAY:
"It's just a quick question about how enquiries are handled when the clinic is busy."
IF they ask again / push for more
SAY:
"John works with clinics on where enquiries get lost before they properly reach the diary."
IF they say "They're with a patient" / "Not available"
SAY:
"Of course. When is best to catch them?"
- If they give a time -> CALL BACK
- If they say email only -> EMAIL FLOW
- If they say "Do you want to leave a message?" -> LEAVE A MESSAGE
IF they say "Send an email"
SAY:
"Of course. Who should I address it to directly?"
- If they give a name -> "Perfect, thanks."
- If they only give a general inbox -> "No problem, I'll send it there."
- Then stop
IF they say "We already have someone" / "We already have a team"
SAY:
"Understood. This isn't about replacing anyone. It's just a quick question about the enquiry side."
- Then ask once: "Would you be able to put me through for 30 seconds?"
- If no -> EMAIL FLOW or EXIT
IF they say "Not interested"
SAY:
"No problem at all. Thanks for your time."
- EXIT
LEAVE A MESSAGE
SAY:
"Yes please, just let them know Bhavisha from Aurea Growth called. It's about how enquiries are handled at the clinic. Thanks."
IF it's voicemail or a recorded system saying "leave your message after the tone" or similar
SAY:
"Hi, Bhavisha from Aurea Growth. Just a quick call about how enquiries are handled at the clinic. Please call us back when convenient. Thanks."
- Then stop
EMAIL FLOW
SAY:
"Perfect. I'll send that over."
- Do not keep pitching
- Do not ask extra questions unless needed to send the email
---
DECISION MAKER
---
OPENING
SAY:
"Hi, Camille here calling on behalf of John Tossou. Quick question, when a patient enquires while you're in the middle of treatment, how does that usually get handled?"
Then stop and listen.
PITCH
After they answer:
1. reflect what they said briefly,
2. explain the gap briefly,
3. ask for a short call.
Example:
"Right, I see. That's exactly the point John looks at. A lot of clinics mean to call people back later, but by then some of the better patients have already gone elsewhere. He just helps tighten that part up so the right enquiries reach the diary properly. Would a short chat this week be worth it?"
If they lean in:
SAY:
"It only needs ten minutes."
---
OBJECTIONS
---
"What exactly is this about?"
-> "It's about where enquiries get lost before they properly reach the diary."
"What do you do?"
-> "John looks at how clinics handle enquiries and where bookings leak before they reach the diary."
"Is this a sales call?"
-> "It's a cold call, yes, but the reason is simple. John helps clinics tighten the point where enquiries get lost."
"Send me more information"
-> "Of course. What's the best email?"
- Once they give it: "Perfect. I'll send that over."
- Stop there
"Not interested"
-> "Understood. Thanks for your time."
"We already have someone"
-> "Understood. This isn't about replacing them. It's about the part between the enquiry coming in and the diary being protected properly."
- Then ask once: "Would a quick look be worth it?"
- If no: exit
"We're happy as we are"
-> "Good to hear. The only reason for the call is that this is often the part clinics think is fine until someone looks closely."
- Then ask once: "Would you at least want to understand it?"
- If no: exit
"I'm with a patient" / "I'm busy"
-> "Of course. When's better, later this week or early next week?"
"Call me back another time"
-> "Of course. What suits you best?"
"We don't have the budget"
-> "Understood. John's call is diagnostic. He just wants to show you what he sees."
- Ask once only if tone is open
"How did you get my number?"
-> "We work with clinics in the space, and John asked me to reach out directly."
"We tried agencies before"
-> "Understood. This isn't an ads conversation. It's about how enquiries are handled once they come in."
"I'm not the decision maker"
-> "No problem. Who is best to speak to about the enquiry side of the clinic?"
"Are you AI?" / "Are you a robot?"
-> "I'm calling on behalf of John about how the clinic handles enquiries."
- If they ask again and sound hostile: "No problem, I'll leave it there. Thanks."
- Do not argue
- Do not deny repeatedly
---
MICRO-COMMITMENT
---
Use only if they are not cold and not hostile.
SAY:
"Does that sound like something you'd at least want to understand?"
If yes -> SECOND ASK
If vague -> PATTERN INTERRUPT
If no -> EXIT
---
PATTERN INTERRUPT
---
Use only with a real decision maker, not reception.
SAY:
"Out of curiosity, how are you currently filtering enquiries before they reach the diary?"
Let them answer.
Then bridge back:
"Right, that's exactly the bit John looks at."
Then:
"Worth ten minutes this week?"
---
SECOND ASK
---
SAY:
"Would earlier or later this week suit you better?"
If yes -> BOOKED
If no -> EXIT
---
BOOKING
---
STEP 1 — Timing gate (ask before offering a slot)
SAY:
"One last question: is this something you want to get ahead of now, or are you OK leaving it as it is for a bit longer?"
If they say later or not sure:
SAY:
"No problem. I will send some information over for when the timing is right. What is the best email?"
-> Go to EMAIL end state. Do not book.
If they confirm it is active now:
SAY:
"Perfect. Are you free for a quick 20 minutes with my boss John this week — does Thursday or Friday work?"
STEP 2 — Lock the slot
"And is morning or afternoon usually better?"
If they give an exact time:
Repeat it back once only.
"Perfect — so John will call you Thursday at 3pm on this number."
STEP 3 — Handoff confirmation
SAY:
"So when John calls, he will be calling about [their specific problem]. You will be expecting that call at [day/time], right?"
STEP 4 — Investment question (do not skip)
SAY:
"Last thing — is there anything specific you want John to look at before he calls? I will make sure he has that context."
Log their exact answer in GHL. This is what John opens with.
STEP 5 — Commitment close
SAY:
"I will send you a reminder on the morning of the call with John's direct number. Does this number work for that text?"
If yes: "Perfect."
If no: ask for the right number.
This is a micro-commitment. When they confirm the reminder, they own the meeting.
STEP 6 — Zeigarnik close (the last thing you say)
SAY:
"Got it. I will make sure John has that before he calls — he will come in with a specific thought on it. Speak soon."
This creates an open loop (what will John find?) that makes the prospect more likely to show up.
Do not add anything after this. Stop talking.
---
EXIT
---
SAY:
"Understood. Thanks for your time."
---
END STATES
---
BOOKED
DO:
- Note name, best number, day/time, email
- Note their specific problem word for word
- Note timing confirmed: ACTIVE NOW (not future)
- Note their answer to the investment question word for word
- This is what John opens with — if it is missing, the booking does not count
QUALIFYING NOTE — must pass before logging as booked:
PASSES: "Runs ads but 30-40% of leads go cold before follow-up. Wants to fix it now."
PASSES: "Gets Google enquiries but no-shows eating diary time. Pre-booking qualification needed. Active now."
FAILS: "Interested in marketing." — no problem, no timing
FAILS: "Said it sounded good." — vague, not a booking reason
FAILS: "Seemed open." — no commitment confirmed
CALL BACK
DO:
- Note best callback window
EMAIL
DO:
- Note email
- Stop
EXIT
DO:
- Log outcome cleanly
Legacy Camille Clinic Script
Reference only. This is the older clinic calling framework.
AUREA GROWTH — CAMILLE CALL SCRIPT v3.3
Simple reference document for outbound calling and callback handling.
Use this document to prepare leads, call clinics, classify outcomes, and move the right follow-up forward.
Core Rule
Call every day.
There is no fixed calling window.
If afternoons work better, use afternoons.
If another time works, use that.
The rule is simple:
- call every day
- move fast
- keep the CRM clean
- use the right angle
- set the right custom disposition after the call
Weekly Target
Minimum: 50 calls per week
That is not for this week only.
That is the standard.
More is better.
Before You Call — 5 Minutes Max
Open the clinic in GHL and confirm the core information first.
A. Base Information
Check these first:
Contact NameContact Phone NumberEmailBusiness Name
If something is obviously wrong, incomplete, generic, or unusable, fix it before calling.
B. Reference Custom Fields
Then check these exact custom fields in GHL:
decision_makerbooking_systemprimary_issuemeta_adsgoogle_adsteam_structureworth_mentioning
These are the reference fields.
They must be usable before the lead is truly call-ready.
That does not mean deep research.
It means fast, practical verification.
Then dial.
How To Find The Information Quickly
Use the fastest source possible. Do not over-research.
1. Google Ads
Check:
Google Transparency Center
Use this to confirm whether the clinic is actively running Google Ads.
2. Meta Ads
Check:
Meta Ads Library
Use this to confirm whether the clinic is actively running Meta Ads.
3. Contact Phone Number
If the phone number is weak, missing, or unclear, use one of these:
- the Clinic Research tool
- the clinic website
About Uspage - Google Reviews / Google Business profile
4. Decision Maker
Use:
- the clinic website
- About page
- practitioner pages
- team page
- existing CRM notes
You are not trying to prove with certainty who owns the business.
You are trying to identify the most likely right person to ask for.
5. Booking System / Primary Issue / Notes
Use:
- website booking flow
- visible booking links
- forms
- call-to-action structure
- existing notes
- any obvious sign of operational friction or weak conversion
Keep it fast.
If it takes too long, move on with the best reasonable judgment.
Opener Priority
Use this order:
- Callback / missed call context -> CALLBACK opener
- They run ads -> GROWTH opener
- No ads, or clinic looks busy / stretched -> AUTOMATION opener
Reception
If you know the decision maker's name:
"Hi, can I speak to Dr Patel please?"
If you do not have a name:
"Hi, can I speak to the person who handles the business side of the clinic?"
If they ask what it is about:
"It's a quick call about clinic growth and where opportunities may be getting lost."
If they are unavailable:
"Of course. When's the best time to reach them?"
If email only:
"Of course. What's the best email?"
Then stop.
Growth Opener
Use when: they run ads
"Hi, this is Camille from Aurea Growth. I can see you're already running ads. Quick question: are you happy with how many enquiries are coming in, or are you still trying to grow that?"
If they want more patients:
"That's exactly what we help with. We help aesthetic clinics grow demand through Google and Meta. Would it be worth a short call this week to see if there's an opportunity?"
If they say they already have an agency / enough marketing:
"Okay, good to know. Is that because you already get enough demand coming in, or are you still trying to grow that side?"
If they already have enough demand, pivot:
"Understood. In that case the bigger opportunity may not be more marketing at all. It may be what happens after the lead comes in — missed calls, slow follow-up, cold leads. Is that ever a problem when the clinic gets busy?"
Automation Opener
Use when: no ads, or clinic looks operationally stretched
"Hi, this is Camille from Aurea Growth. We help busy clinics make sure missed calls, slow follow-up, and cold leads don't slip when things get hectic. Quick question: when you're with a patient and something comes in, are you confident it always gets handled properly?"
If they have that problem:
"That's exactly what we fix. Would it be worth a short call this week to take a look?"
If they say they are fine / that is not an issue:
"Good to hear. In that case, is the bigger opportunity simply getting more of the right enquiries in?"
If yes, pivot to growth.
Callback / Missed Call Opener
"Hi, this is Camille from Aurea Growth. I tried to reach you earlier and no one picked up — that's actually the exact gap we help clinics fix. Quick question: when the clinic is busy, are enquiries and callbacks always getting handled?"
Objections — Use As Pivots
"We already work with an agency"
"Okay, good to know. Is that because you still want more demand coming in, or because you already get enough demand and the bigger challenge is handling it all properly?"
If they already get enough leads:
"That makes sense. That's exactly where we help as well. For some clinics the problem is not more marketing — it's making sure calls, leads, and follow-up don't slip when things get busy."
"Not interested"
"Fair enough. Is that because things are going well on the demand side, or because marketing is not the priority right now?"
Use the answer to understand the context before closing.
"We're fine"
"Good to hear. I'm just checking whether there's still room to grow — either more demand coming in, or making the handling tighter."
"Send me information"
"Of course. What's the best email?"
Then stop.
"I'm busy"
"Of course. When's better to catch you?"
"How much?"
"Depends on what's needed — that's what the short call is for."
"What is this about?"
"Helping clinics get more patients, or making sure enquiries don't slip when things get busy."
Booking
"Would it make sense to have a quick call this week?"
If yes:
"Great. What number is best, and is morning or afternoon easier for you?"
Repeat the time back once. Then stop talking.
After The Call — Always Do This
- Set the correct custom disposition in GHL
- Follow the workflow that gets triggered from that custom disposition
- Take the action required inside that workflow
Do not add manual tags unless there is a very specific reason.
The workflows should handle the tagging logic.
Your job is to set the right custom disposition and then follow through properly.
Final Rule
Your job is not to overthink.
Your job is to:
- check the base information
- confirm the reference custom fields
- choose the right opener
- make the call
- set the right custom disposition
- follow the workflow
- do it again the next day
That is the system.
Activation Prompt
You are in Intelligence Graph mode. Read docs/intelligence-graph-sop.md (all sections including 15) before doing anything. The system has two layers: intelligence/companies/ (account memory, synced to GHL via /intel-update) and intelligence/people/ (relationship memory, never synced to GHL). Active products: corvidae, gimii, aurea. Pixis dropped. Core daily loop: /daily-outreach (see what is due), /prep-touch [Company] [product] (create Touch 2/3 draft), send from Gmail, /log-sent [Company] [product] after each send. Batch new pipeline: /research-batch [N] [product] on Sunday or when pipeline is thin. Never use /log-sent or /prep-touch for job contacts — use /person-update [Name] session instead. Use /intel-update for Touch 1 outreach prep and post-call notes. Use /thread-closeout after a real reply or meeting. Use /oracle-query for natural language searches across the intelligence layer. People layer: filename is always Firstname-Lastname.md — never changes on job change. Interview contacts stay in people files only, never GHL.
Intelligence Graph — Full System SOP
This is the canonical reference for the Oracle Intelligence Graph: a private, compounding knowledge base of every person and company John has a commercial or career relationship with. It lives outside GHL on purpose — GHL is the execution layer (notes, tasks, sequences), this is the memory layer (who they are, what they want, what John can offer them, what's owed).
1. What This System Is
The goal: John processes more data points about more contacts than anyone else in his network, and never shows up cold. Every call, LinkedIn signal, referral, and brain dump gets captured once, structured, and made queryable forever.
Two file types:
- Company files (intelligence/companies/) — account memory. Source of truth for Gimii/Corvidae sales research, synced to GHL.
- Person files (intelligence/people/) — relationship memory. Source of truth for who John knows, what they care about, and what's owed between them. Never synced to GHL.
As of 2026-06-30: 4 company files, 98 person files live.
2. Architecture
intelligence/
├── companies/
│ ├── _TEMPLATE.md
│ └── [4 live files — The-Guardian.md, etc.]
├── people/
│ ├── _TEMPLATE.md
│ └── [98 live files]
├── taxonomy/
│ └── tags.md ← all valid frontmatter values, single source of truth
└── .field-ids.json ← GHL custom field IDs used by company sync (intel-update)
3. Naming Convention
- Companies:
Company-Name.md, title-cased, spaces to hyphens. e.g. "the guardian" →The-Guardian.md - People:
Firstname-Lastname.md, title-cased, spaces to hyphens. e.g. "jack oddy" →Jack-Oddy.md - People filenames are canonical and never change when someone changes jobs. A job change updates the
company:frontmatter field and prepends a note to Relationship History — the filename stays exactly the same. This is the whole point: the file follows the person, not the employer. - If the last name isn't known yet, use a temporary identifier (e.g.
Jack-TagDigital.md) and flag it in the file body until confirmed.
4. Tag Schema (Frontmatter)
Full valid-value reference lives in intelligence/taxonomy/tags.md. Summary:
type: company | person
relationship_type: prospect | client | interview | peer | advisor | connector | investor | partner
relationship_stage: unknown → aware → connected → replied → call_done → trusted → active_partner
# progression model — each stage implies all prior stages are complete
relationship_strength: 1-5
# 1 cold/acquaintance, 2 met/light, 3 warm/replied, 4 strong/recurring, 5 trusted inner circle
domain: [adtech, publishing, martech, saas, fintech, sport, beauty-wellness, ecommerce, agency, fmcg, telecom, luxury]
interest: [sports, football, sustainability, charity, privacy, first-party-data, ai, investing, entrepreneurship]
goal: [job-search, fundraising, hiring, partnerships, growth, career-change, advisory]
expertise: [free text — e.g. google-ads, programmatic, media-buying]
company: # current employer slug, must match a companies/ filename if one exists
past_company: [] # array, previous employers
linked_company: # for company files only — cross-reference if relevant
Important boundary: relationship_type: interview is for job-search contacts (people interviewing John or being interviewed by John for a role). These contacts never go in GHL — GHL is a sales CRM, interview contacts are not sales prospects.
5. Person File Schema
---
type: person
relationship_type: ...
relationship_stage: ...
relationship_strength: ...
domain: []
interest: []
goal: []
expertise: []
company:
past_company: []
linked_company:
---
# [Full Name]
## Identity
Current role, company, past companies, location, how we met, relationship to John
## Personal Signals
- [Signal] | Source: LinkedIn/call/email/article | Confidence: high/medium/low | Sensitivity: public/private/delicate
## Professional Goals
- Same per-signal metadata as Personal Signals
## Relationship History
### YYYY-MM-DD — [Channel] — [Topic]
Newest first.
## Value Ledger
Value given / Value promised / Value requested / Intros made / Intros owed
## Access Paths
Mutuals, past colleagues, best intro path, communities/events, reason they may help
## Sensitive / Do Not Mention
Info for understanding only — family, health, confidential job search, salary. Never used as a conversation hook.
## People They Know
Name — Company — Why relevant
## Next Best Action
Action / Due / Reason
Every signal carries three pieces of metadata: Source (where it came from), Confidence (how sure), Sensitivity (public = safe to reference directly, private = know but don't quote, delicate = understanding only, never surfaced in outreach). /oracle-query and /relationship-feed both filter out Sensitivity: delicate signals from anything that could become an outreach angle.
6. Command: /intel-update [Company]
Usage: /intel-update [Company] (pre-outreach) or /intel-update [Company] session (post-call)
The only command that writes to GHL. Two modes:
Pre-outreach mode (default): brain dump → hook quality gate → update company file → sync 7 GHL custom fields + note + tags → generate Gmail draft.
Session mode (trailing "session"): call/meeting notes → append Outreach History → sync GHL note + tags → create next-step task. No email draft.
Key mechanics:
- Reads field IDs from intelligence/.field-ids.json. Halts if not set up — run python3 tools/setup_ghl_outreach_fields.py first.
- Hook quality gate (pre-outreach only): classifies the hook as Strong / Medium / Weak. Weak hooks get rejected with a suggested stronger angle — the command will not let a generic email go out.
- Account suppression check: if any contact at the company already has account:active-conversation, it warns before adding a parallel cold sequence.
- GHL note format is capped at 5 lines, mobile-readable.
- Custom fields pushed: hook, hook subject, CMP vendor, product fit, account type, buying signal, last-intel-update date. Blank fields are never sent — would overwrite correct data with nothing.
- Touch number and CTA variant (direct-buyer / referral / technical-validation / routing / reopen) are auto-detected from existing GHL tags.
- Session mode adds account:active-conversation to ALL contacts at that company if the outcome is replied or meeting-booked — this is account-level suppression, not just the one contact.
- Referrals surfaced in session notes auto-create a stub company file from _TEMPLATE.md.
7. Command: /daily-outreach
Usage: /daily-outreach — no arguments.
Read-only morning ops queue. Pulls every GHL contact (paginated), cross-references tasks, runs stale detection, and (if Gmail MCP is connected) scans for no-reply threads via the /follow-up skill.
Outputs up to 8 sections (omits any with zero entries):
1. SEND TODAY — task due today/overdue + draft:ready or hook:needed
2. REPLIES NEEDING RESPONSE — tagged reply:needs-response
3. DRAFTS READY TO REVIEW — draft:ready, no task due yet
4. MISSING HOOKS — enrolled in a sequence but hook:needed
5. WARM / MANUAL-ONLY — manual-only or account:active-conversation, must not enter cold sequences
6. STALE — NO NEXT ACTION — no reply tag, no sequence, no sent touch, no task in next 7 days, untouched 14+ days
7. FOLLOW-UPS FROM GMAIL — via /follow-up skill scan
8. SUGGESTED NEXT RESEARCH — tagged research:needed, grouped by product fit
Ends with: To act: /intel-update "[Company]" to draft | /thread-closeout "[Company]" after a reply or call
8. Command: /thread-closeout [Company]
Usage: /thread-closeout [Company Name]
More structured than /intel-update session — use this specifically after a real reply or meeting, when the goal is to formally close out the live thread state (stop sequences, log outcome, set next task).
Flow: load company file → ask for outcome (replied / meeting-booked / not-interested / referral-given / hold) → ask for contact name → ask for notes → update Outreach History + NBA + Stakeholders → GHL tag remap per outcome table → push GHL note → create next-step task → handle referral if mentioned → confirm.
Outcome → tag mapping:
| Outcome | Adds | Removes |
|---|---|---|
| replied | status:replied, reply:needs-response |
sequence tags, sent:* |
| meeting-booked | status:meeting-booked |
sequence tags, sent:* |
| not-interested | status:not-relevant |
sequence tags, sent:* |
| referral-given | status:replied |
sequence tags, sent:* |
| hold | hold |
sequence tags only (keeps sent:* — thread may resume) |
replied and meeting-booked also add account:active-conversation to every contact at that company.
9. Command: /person-update [Name]
Usage: /person-update [Name] | /person-update [Name] session | /person-update [Name] job-change
The only command that writes to person files. Never syncs to GHL — this is the hard boundary of the whole system.
Three modes:
- default: full brain dump → extracts personal signals, professional goals, relationship history, value ledger, access paths, sensitive info, people-they-know, NBA. Cross-references the linked company file's Stakeholders table if one exists.
- session: post-call notes → appends Relationship History only, updates stage/strength/NBA.
- job-change: updates company: frontmatter (old value moves to past_company:), prepends a Relationship History note. Filename never changes.
relationship_stage/relationship_strength are raised when warranted, never lowered without an explicit signal.
10. Command: /oracle-query [Question]
Usage: /oracle-query [Question] — natural language. Read-only, no writes.
Runs cd "Claude Code Workflow" && qmd search "<question>" -c intelligence -n 12. Falls back to a direct filesystem scan of intelligence/companies/ and intelligence/people/ if the collection isn't indexed (prints the qmd collection add command to fix it).
Groups results into three tiers:
- DIRECT MATCHES — strong signal + stage ≥ replied + strength ≥ 3
- ADJACENT — relevant but lower stage/strength
- WEAK SIGNAL — loosely relevant
Never surfaces relationship_stage: unknown contacts unless nothing better exists, and never surfaces Sensitivity: delicate signals as outreach hooks. Ends with one concrete SUGGESTED MOVE.
11. Command: /relationship-feed
Usage: /relationship-feed — no arguments. Read-only morning scan of all person files.
Five buckets (a contact can appear in more than one; empty buckets are omitted):
- RECONNECT TODAY — NBA due date ≤ today
- RECONNECT THIS WEEK — NBA due within 7 days
- DORMANT WARM CONTACTS — last contact 90+ days ago AND strength ≥ 3
- JOB SEARCH RADAR — goal: job-search in frontmatter
- PROMISES TO KEEP — non-blank "Value promised" or "Intros owed"
relationship_stage: unknown contacts never appear in RECONNECT sections (never been contacted yet). Dormant-contact suggested angles always come from the person's own Professional Goals/Personal Signals/Value Ledger — never generic.
12. GHL vs Intelligence Boundary
This is the rule that keeps the system clean. Get this wrong and GHL fills with noise or the intelligence layer goes stale.
| Company files | GHL | |
|---|---|---|
| What it is | Source of truth: research, hooks, history, NBAs | Execution layer: notes, custom fields, tags, tasks, Gmail drafts |
| Who writes it | /intel-update, /thread-closeout |
Synced automatically by the same two commands |
| Read by | /oracle-query, /daily-outreach |
Aubrey/Camille (trades pipeline — separate from this system) |
| Person files | GHL | |
|---|---|---|
| Synced? | Never. Intelligence-only. | N/A |
| Why | Person files track relationships across jobs, careers, and contexts that have nothing to do with active sales sequences. Putting them in a sales CRM would either spam them into cold sequences or get deleted in a CRM cleanup. | |
| Interview contacts | People files only. Never GHL — GHL is a sales CRM, job-search contacts are not sales prospects. |
Rule of thumb: if it's about closing a deal, it's GHL-bound (via the company file). If it's about a relationship that may or may not ever become commercial, it stays in the people layer only.
13. QMD Search
The intelligence layer is indexed as a QMD collection covering intelligence/people/*.md and intelligence/companies/*.md (38 documents indexed as of the 2026-06-30 build, growing as files are added).
Direct search:
cd "Claude Code Workflow" && qmd search "<question>" -c intelligence -n 10
Prefer /oracle-query over raw qmd search for anything outreach-facing — it adds the stage/strength tiering, sensitivity filtering, and a concrete suggested move that raw search output doesn't give you. Use raw qmd search only for quick manual lookups when you don't need structured output.
If the collection ever needs rebuilding:
cd "Claude Code Workflow" && qmd collection add intelligence intelligence/ && qmd update && qmd embed -c intelligence
14. Daily Workflow — Research to GHL
This is the repeating loop. The system is only useful if it gets fed. Every signal that goes into a file instead of getting forgotten is compounding advantage.
Morning (5 minutes)
Run these two in order at the start of the day:
/daily-outreach
/relationship-feed
/daily-outreach gives you the GHL ops queue: what to send today, what to follow up, what has gone stale. /relationship-feed gives you the relationship layer: people you owe a reconnect, promises outstanding, warm contacts going cold. Together they replace any manual CRM triage.
Do not open GHL first. These commands pull everything you need.
Trigger → Action Map
Use this when something lands in your inbox, feed, or head and you're not sure which command to reach for.
| What happened | Command |
|---|---|
| You found news, a LinkedIn post, a meeting note, or a Google Doc about a company you want to approach | /intel-update [Company] |
| A prospect replied to an email | /intel-update [Company] session |
| You had a call or meeting with a prospect | /thread-closeout [Company] |
| You learned something new about a person (job change, LinkedIn signal, something said on a call) | /person-update [Name] |
| You want to know who in your network is relevant to a topic or opportunity | /oracle-query [Question] |
| You have intel but it's about a person only, not a company deal | /person-update [Name] — never /intel-update |
| Someone at a company you're already tracking referred you to someone at a different company | Note it in /intel-update [Company] session — it auto-creates a stub file for the referred company |
Research → Intel File → GHL: The Flow
This is the core loop for Gimii and Corvidae outreach. Every contact goes through it once before any email goes out.
Step 1 — Find a signal. Can be anything: a news article, a LinkedIn post about a product launch, meeting notes from a partner call, a Google Doc shared with you, a Slack message from a prospect. The signal just needs to give you a specific, concrete hook — something that maps to a real pressure for that person's role.
Step 2 — Run /intel-update [Company]. Paste the signal as the brain dump. The command:
- Classifies hook quality (Strong / Medium / Weak). Weak hooks get rejected with a suggested angle — this is a quality gate, not a rubber stamp.
- Creates or updates intelligence/companies/[Company].md.
- Searches GHL for existing contacts. If none exist, creates them.
- Pushes a structured note + 7 custom fields to every contact at that company.
- Sets the right tags (draft:ready, client:gimii / client:corvidae, etc.).
- Prints the email text ready to paste. No Gmail drafts are created automatically.
Step 3 — Send the email manually. Copy the printed text, paste into Gmail, send. The command does not send on your behalf.
Step 4 — When a reply comes back. Run /intel-update [Company] session with the reply context, or /thread-closeout [Company] if it's a real conversation with an outcome (replied, meeting booked, not interested). This logs the outcome, updates GHL tags, and creates the next-step task.
What Goes Where: The Hard Rules
These boundaries keep the system clean. Break them and GHL fills with noise or the intelligence layer goes stale.
Into company files only (via /intel-update or /thread-closeout):
- Research, hooks, outreach history, next best actions for active Gimii/Corvidae deals
- Anything that will feed a GHL sequence or task
Into person files only (via /person-update):
- Relationship context: what someone cares about, what's owed, personal signals
- Job-search contacts (interviewers, hiring managers) — never GHL
- Anyone you know personally or professionally who is not an active sales target
Never:
- Put interview/job-search contacts in GHL
- Write directly to GHL without going through the intelligence layer first
- Let a company file go more than 14 days without an NBA entry if there's an active thread
The Research-to-GHL Boundary
GHL does not drive research. Research drives GHL.
The correct direction is: you find a signal → intel file captures it → GHL gets synced from the intel file. Never the reverse. If you find yourself adding a contact in GHL first and then trying to figure out what to say, you've skipped the step that makes the email good.
The 7 custom fields pushed to GHL (email_hook, email_hook_subject, cmp_vendor, product_fit, account_type, buying_signal, last_intel_update) are all derived from the intel file. They exist in GHL so that if Camille or Aubrey ever need context on a contact, they can see it without reading the markdown. But the markdown is the source of truth — GHL is a read-only view of it for execution purposes.
15. Outreach Automation Commands
Three commands built on top of the intelligence layer to remove the manual tracking overhead of multi-touch outreach. Together they eliminate the need to open gimii-continuous-outreach-template.md or corvidae/PROJECT-corvidae.md every morning.
Products in scope: corvidae, gimii, aurea. Not Pixis. Job-search contacts use /person-update, not these commands.
/log-sent [Company] [corvidae|gimii|aurea|job]
Run this after clicking Send in Gmail. Takes 5 seconds. Marks the touch in GHL and creates a follow-up task so /daily-outreach surfaces Touch 2/3 when it comes due.
What it does:
1. GHL search by company name → identifies the contact
2. Reads existing sent:* tags to determine which touch number this was
3. Adds sent:[product]-touch-[N] tag, removes draft:ready
4. Posts a note: [Sent — YYYY-MM-DD] Touch [N] sent via Gmail.
5. Creates a GHL task titled [product] Touch [N+1] due — [Company] — [Contact Full Name] due 7 days from today (Touch 1 and 2 only)
Task title format matters — /daily-outreach matches on * Touch * due — * — * to find follow-ups. Don't edit these task titles manually.
If job is passed as the product: prints a redirect to /person-update and halts — job contacts never go in GHL.
/prep-touch [Company] [corvidae|gimii|aurea]
Run this when /daily-outreach shows a Touch 2 or Touch 3 task is due. Creates the Gmail draft using the correct fixed template. John reviews, tweaks if needed, and clicks Send.
What it does:
1. Reads the company intel file for hook, contact name, original subject line
2. GHL lookup for contact email and email_hook_subject custom field
3. Detects touch number from existing sent:* tags
4. Generates the correct fixed-template email (see templates in the command file)
5. Creates Gmail draft via MCP. If MCP unavailable: prints the email as plain text for manual paste.
Fixed templates by product and touch:
- Corvidae Touch 2: Subject One thought I should have led with — Consent Mode v2 → weak Smart Bidding signal → Corvidae fix → is this worth picking back up?
- Corvidae Touch 3: Subject Closing the loop — referral ask or close
- Gimii Touch 2: Subject Re: [original subject] — consent recovery follow-up, is this worth routing internally?
- Gimii Touch 3: Subject Closing the loop — route internally or close
- Aurea Touch 2: Subject One thing I should have led with — clinic intake/no-show pain, worth 20 minutes?
- Aurea Touch 3: Subject Closing the loop — better time or different contact?
After the draft is created: run /log-sent [Company] [product] once you've clicked Send.
/research-batch [N] [corvidae|gimii|aurea|all]
Batch Touch 1 prep. Use Sunday or when the pipeline is thin. Surfaces the N most-neglected uncontacted targets, runs /intel-update for each, and creates Touch 1 Gmail drafts.
What it does:
1. GHL fetch all contacts (paginated)
2. Filters out: any contact with sent:* tags, status:not-relevant, hold, account:active-conversation, status:sequence-complete
3. Filters by product_fit custom field if product ≠ all
4. Sorts by last_intel_update ascending — oldest/least-touched first
5. Lists top N for confirmation (yes / skip [name] / stop)
6. For each confirmed: runs /intel-update (which prompts for brain dump, runs hook quality gate, creates Gmail draft)
7. Reports total drafts created
Defaults: N = 10, product = all.
This command handles new Touch 1s only. Follow-ups (Touch 2/3) are handled by /daily-outreach + /prep-touch.
How they connect: the daily loop
Morning:
/daily-outreach
→ TOUCH 2/3 DUE TODAY section shows tasks due
→ /prep-touch [Company] [product] for each one → Gmail draft created
Open Gmail Drafts → review → click Send
/log-sent [Company] [product] after each send
Replies → /thread-closeout [Company]
When pipeline is thin (Sunday or as needed):
/research-batch 10 all → Touch 1 drafts for N new targets
The trigger → action map from Section 14 now extends to:
| What happened | Command |
|---|---|
| You sent an email from Gmail | /log-sent [Company] [product] |
| /daily-outreach shows a Touch 2 or 3 due | /prep-touch [Company] [product] |
| Pipeline needs new Touch 1 contacts | /research-batch [N] [product] |
Input Formats Accepted by /intel-update
The brain dump can be:
- Pasted text — a news article, LinkedIn post, email thread, Slack message
- A screenshot — paste the image directly; the command reads it
- A Google Doc URL — the command reads the doc via Drive MCP and parses the content
- Your own notes — bullet points, fragments, stream of consciousness — any format works
You do not need to clean up or structure the input. The command extracts what it needs.
Frequency Guide
| Activity | Cadence |
|---|---|
/daily-outreach + /relationship-feed |
Every working day, first thing |
/intel-update [Company] (new prospect) |
Whenever a signal lands — do not batch, do it while the context is fresh |
/intel-update [Company] session (reply received) |
Same day as the reply, before the context fades |
/thread-closeout [Company] (call/meeting done) |
Same day as the call |
/person-update [Name] |
After any call, or when a LinkedIn signal is relevant enough to capture |
/oracle-query |
When you're entering a new vertical, prepping for a meeting, or trying to find a warm path |
/relationship-feed (deep review) |
Once a week minimum — dormant warm contacts decay fast |
Client Pages, CRO & SEO
/ab-test-setup
local
When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also.
When: When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also.
/ai-seo
local
When the user wants to optimize content for AI search engines, get cited by LLMs, or appear in AI-generated answers. Also.
When: When the user wants to optimize content for AI search engines, get cited by LLMs, or appear in AI-generated answers. Also.
/analytics-tracking
local
When the user wants to set up, improve, or audit analytics tracking and measurement. Also.
When: When the user wants to set up, improve, or audit analytics tracking and measurement. Also.
/aso-audit
local
When the user wants to audit or optimize an App Store or Google Play listing. Also.
When: When the user wants to audit or optimize an App Store or Google Play listing. Also.
/churn-prevention
local
When the user wants to reduce churn, build cancellation flows, set up save offers, recover failed payments, or implement retention strategies. Also.
When: When the user wants to reduce churn, build cancellation flows, set up save offers, recover failed payments, or implement retention strategies. Also.
/client-landing-page-builder
local
End-to-end Aurea Growth landing page builder for clinic/client campaigns.
When: End-to-end Aurea Growth landing page builder for clinic/client campaigns.
/form-cro
local
When the user wants to optimize any form that is NOT signup/registration — including lead capture forms, contact forms, demo request forms, application forms, survey forms, or checkout...
When: When the user wants to optimize any form that is NOT signup/registration — including lead capture forms, contact forms, demo request forms, application forms, survey forms, or checkout forms. Also.
/onboarding-cro
local
When the user wants to optimize post-signup onboarding, user activation, first-run experience, or time-to-value. Also.
When: When the user wants to optimize post-signup onboarding, user activation, first-run experience, or time-to-value. Also.
/page-cro
local
When the user wants to optimize, improve, or increase conversions on any marketing page — including homepage, landing pages, pricing pages, feature pages, or blog posts. Also.
When: When the user wants to optimize, improve, or increase conversions on any marketing page — including homepage, landing pages, pricing pages, feature pages, or blog posts. Also.
/paywall-upgrade-cro
local
When the user wants to create or optimize in-app paywalls, upgrade screens, upsell modals, or feature gates. Also.
When: When the user wants to create or optimize in-app paywalls, upgrade screens, upsell modals, or feature gates. Also.
/popup-cro
local
When the user wants to create or optimize popups, modals, overlays, slide-ins, or banners for conversion purposes. Also.
When: When the user wants to create or optimize popups, modals, overlays, slide-ins, or banners for conversion purposes. Also.
/programmatic-seo
local
When the user wants to create SEO-driven pages at scale using templates and data. Also.
When: When the user wants to create SEO-driven pages at scale using templates and data. Also.
/schema-markup
local
When the user wants to add, fix, or optimize schema markup and structured data on their site. Also.
When: When the user wants to add, fix, or optimize schema markup and structured data on their site. Also.
/seo-audit
local
When the user wants to audit, review, or diagnose SEO issues on their site. Also.
When: When the user wants to audit, review, or diagnose SEO issues on their site. Also.
/signup-flow-cro
local
When the user wants to optimize signup, registration, account creation, or trial activation flows. Also.
When: When the user wants to optimize signup, registration, account creation, or trial activation flows. Also.
/site-architecture
local
When the user wants to plan, map, or restructure their website's page hierarchy, navigation, URL structure, or internal linking. Also.
When: When the user wants to plan, map, or restructure their website's page hierarchy, navigation, URL structure, or internal linking. Also.
Premium Design & Frontend
/adapt [target] [context (mobile, tablet, print...)]
system
Adapt designs to work across different screen sizes, devices, contexts, or platforms. Implements breakpoints, fluid layouts, and touch targets.
When: Adapt designs to work across different screen sizes, devices, contexts, or platforms. Implements breakpoints, fluid layouts, and touch targets.
/animate [target]
system
Review a feature and enhance it with purposeful animations, micro-interactions, and motion effects that improve usability and delight.
When: Review a feature and enhance it with purposeful animations, micro-interactions, and motion effects that improve usability and delight.
/audit [area (feature, page, component...)]
system
Run technical quality checks across accessibility, performance, theming, responsive design, and anti-patterns. Generates a scored report with P0-P3 severity ratings and actionable plan.
When: Run technical quality checks across accessibility, performance, theming, responsive design, and anti-patterns. Generates a scored report with P0-P3 severity ratings and actionable plan.
/bolder [target]
system
Amplify safe or boring designs to make them more visually interesting and stimulating. Increases impact while maintaining usability.
When: Amplify safe or boring designs to make them more visually interesting and stimulating. Increases impact while maintaining usability.
/clarify [target]
system
Improve unclear UX copy, error messages, microcopy, labels, and instructions to make interfaces easier to understand.
When: Improve unclear UX copy, error messages, microcopy, labels, and instructions to make interfaces easier to understand.
/colorize [target]
system
Add strategic color to features that are too monochromatic or lack visual interest, making interfaces more engaging and expressive.
When: Add strategic color to features that are too monochromatic or lack visual interest, making interfaces more engaging and expressive.
/critique [area (feature, page, component...)]
system
Evaluate design from a UX perspective, assessing visual hierarchy, information architecture, emotional resonance, cognitive load, and overall quality with quantitative scoring...
When: Evaluate design from a UX perspective, assessing visual hierarchy, information architecture, emotional resonance, cognitive load, and overall quality with quantitative scoring, persona-based testing, automated...
/delight [target]
system
Add moments of joy, personality, and unexpected touches that make interfaces memorable and enjoyable to use. Elevates functional to delightful.
When: Add moments of joy, personality, and unexpected touches that make interfaces memorable and enjoyable to use. Elevates functional to delightful.
/design-an-interface
local
Generate multiple radically different interface designs for a module using parallel sub-agents.
When: Generate multiple radically different interface designs for a module using parallel sub-agents.
/design-taste-frontend
system
Senior UI/UX Engineer. Architect digital interfaces overriding default LLM biases. Enforces metric-based rules, strict component architecture, CSS hardware acceleration, and balanced design...
When: Senior UI/UX Engineer. Architect digital interfaces overriding default LLM biases. Enforces metric-based rules, strict component architecture, CSS hardware acceleration, and balanced design engineering.
/distill [target]
system
Strip designs to their essence by removing unnecessary complexity. Great design is simple, powerful, and clean.
When: Strip designs to their essence by removing unnecessary complexity. Great design is simple, powerful, and clean.
/emil-design-eng
system
This skill encodes Emil Kowalski's philosophy on UI polish, component design, animation decisions, and the invisible details that make software feel great.
When: This skill encodes Emil Kowalski's philosophy on UI polish, component design, animation decisions, and the invisible details that make software feel great.
/frontend-design
local
When the user wants to improve, redesign, or build a UI — Flask templates, HTML/CSS, dashboards, admin panels. Trigger on "improve the UI", "redesign this page", "make this look better"...
When: When the user wants to improve, redesign, or build a UI — Flask templates, HTML/CSS, dashboards, admin panels. Trigger on "improve the UI", "redesign this page", "make this look better", "the UI is functional...
/full-output-enforcement
system
Overrides default LLM truncation behavior. Enforces complete code generation, bans placeholder patterns, and handles token-limit splits cleanly. Apply to any task requiring exhaustive...
When: Overrides default LLM truncation behavior. Enforces complete code generation, bans placeholder patterns, and handles token-limit splits cleanly. Apply to any task requiring exhaustive, unabridged output.
/gpt-taste
system
Elite UX/UI & Advanced GSAP Motion Engineer. Enforces Python-driven true randomization for layout variance, strict AIDA page structure, wide editorial typography (bans 6-line wraps)...
When: Elite UX/UI & Advanced GSAP Motion Engineer. Enforces Python-driven true randomization for layout variance, strict AIDA page structure, wide editorial typography (bans 6-line wraps), gapless bento grids...
/gsap
local
GSAP animation reference for HyperFrames. Covers gsap.to(), from(), fromTo(), easing, stagger, defaults, timelines (gsap.timeline(), position parameter, labels, nesting, playback), and...
When: GSAP animation reference for HyperFrames. Covers gsap.to(), from(), fromTo(), easing, stagger, defaults, timelines (gsap.timeline(), position parameter, labels, nesting, playback), and performance (transforms...
/high-end-visual-design
system
Teaches the AI to design like a high-end agency. Defines the exact fonts, spacing, shadows, card structures, and animations that make a website feel expensive. Blocks all the common...
When: Teaches the AI to design like a high-end agency. Defines the exact fonts, spacing, shadows, card structures, and animations that make a website feel expensive. Blocks all the common defaults that make AI...
/impeccable [craft|teach|extract]
system
Create distinctive, production-grade frontend interfaces with high design quality. Generates creative, polished code that avoids generic AI aesthetics.
When: Create distinctive, production-grade frontend interfaces with high design quality. Generates creative, polished code that avoids generic AI aesthetics.
/industrial-brutalist-ui
system
Raw mechanical interfaces fusing Swiss typographic print with military terminal aesthetics. Rigid grids, extreme type scale contrast, utilitarian color, analog degradation effects. For...
When: Raw mechanical interfaces fusing Swiss typographic print with military terminal aesthetics. Rigid grids, extreme type scale contrast, utilitarian color, analog degradation effects. For data-heavy dashboards...
/layout [target]
system
Improve layout, spacing, and visual rhythm. Fixes monotonous grids, inconsistent spacing, and weak visual hierarchy.
When: Improve layout, spacing, and visual rhythm. Fixes monotonous grids, inconsistent spacing, and weak visual hierarchy.
/minimalist-ui
system
Clean editorial-style interfaces. Warm monochrome palette, typographic contrast, flat bento grids, muted pastels. No gradients, no heavy shadows.
When: Clean editorial-style interfaces. Warm monochrome palette, typographic contrast, flat bento grids, muted pastels. No gradients, no heavy shadows.
/optimize [target]
system
Diagnoses and fixes UI performance across loading speed, rendering, animations, images, and bundle size.
When: Diagnoses and fixes UI performance across loading speed, rendering, animations, images, and bundle size.
/overdrive [target]
system
Pushes interfaces past conventional limits with technically ambitious implementations — shaders, spring physics, scroll-driven reveals, 60fps animations.
When: Pushes interfaces past conventional limits with technically ambitious implementations — shaders, spring physics, scroll-driven reveals, 60fps animations.
/polish [target]
system
Performs a final quality pass fixing alignment, spacing, consistency, and micro-detail issues before shipping.
When: Performs a final quality pass fixing alignment, spacing, consistency, and micro-detail issues before shipping.
/quieter [target]
system
Tones down visually aggressive or overstimulating designs, reducing intensity while preserving quality.
When: Tones down visually aggressive or overstimulating designs, reducing intensity while preserving quality.
/redesign-existing-projects
system
Upgrades existing websites and apps to premium quality. Audits current design, identifies generic AI patterns, and applies high-end design standards without breaking functionality. Works...
When: Upgrades existing websites and apps to premium quality. Audits current design, identifies generic AI patterns, and applies high-end design standards without breaking functionality. Works with any CSS framework...
/shape [feature to shape]
system
Plan the UX and UI for a feature before writing code. Runs a structured discovery interview, then produces a design brief that guides implementation. Use during the planning phase to...
When: Plan the UX and UI for a feature before writing code. Runs a structured discovery interview, then produces a design brief that guides implementation. Use during the planning phase to establish design...
/stitch-design-taste
system
Semantic Design System Skill for Google Stitch. Generates agent-friendly DESIGN.md files that enforce premium, anti-generic UI standards — strict typography, calibrated color, asymmetric...
When: Semantic Design System Skill for Google Stitch. Generates agent-friendly DESIGN.md files that enforce premium, anti-generic UI standards — strict typography, calibrated color, asymmetric layouts, perpetual...
/typeset [target]
system
Improves typography by fixing font choices, hierarchy, sizing, weight, and readability so text feels intentional.
When: Improves typography by fixing font choices, hierarchy, sizing, weight, and readability so text feels intentional.
Marketing, Copy & Growth
/ad-creative
local
When the user wants to generate, iterate, or scale ad creative — headlines, descriptions, primary text, or full ad variations — for any paid advertising platform. Also.
When: When the user wants to generate, iterate, or scale ad creative — headlines, descriptions, primary text, or full ad variations — for any paid advertising platform. Also.
/cold-email
local
Write B2B cold emails and follow-up sequences that get replies.
When: Write B2B cold emails and follow-up sequences that get replies.
/community-marketing
local
Build and leverage online communities to drive product growth and brand loyalty.
When: Build and leverage online communities to drive product growth and brand loyalty.
/competitor-alternatives
local
When the user wants to create competitor comparison or alternative pages for SEO and sales enablement. Also.
When: When the user wants to create competitor comparison or alternative pages for SEO and sales enablement. Also.
/content-strategy
local
When the user wants to plan a content strategy, decide what content to create, or figure out what topics to cover. Also.
When: When the user wants to plan a content strategy, decide what content to create, or figure out what topics to cover. Also.
/copy-editing
local
When the user wants to edit, review, or improve existing marketing copy, or refresh outdated content. Also.
When: When the user wants to edit, review, or improve existing marketing copy, or refresh outdated content. Also.
/copywriting
local
When the user wants to write, rewrite, or improve marketing copy for any page — including homepage, landing pages, pricing pages, feature pages, about pages, or product pages. Also.
When: When the user wants to write, rewrite, or improve marketing copy for any page — including homepage, landing pages, pricing pages, feature pages, about pages, or product pages. Also.
/customer-research
local
When the user wants to conduct, analyze, or synthesize customer research.
When: When the user wants to conduct, analyze, or synthesize customer research.
/edit-article
local
Edit and improve articles by restructuring sections, improving clarity, and tightening prose.
When: Edit and improve articles by restructuring sections, improving clarity, and tightening prose.
/email-sequence
local
When the user wants to create or optimize an email sequence, drip campaign, automated email flow, or lifecycle email program. Also.
When: When the user wants to create or optimize an email sequence, drip campaign, automated email flow, or lifecycle email program. Also.
/free-tool-strategy
local
When the user wants to plan, evaluate, or build a free tool for marketing purposes — lead generation, SEO value, or brand awareness. Also.
When: When the user wants to plan, evaluate, or build a free tool for marketing purposes — lead generation, SEO value, or brand awareness. Also.
/launch-strategy
local
When the user wants to plan a product launch, feature announcement, or release strategy. Also.
When: When the user wants to plan a product launch, feature announcement, or release strategy. Also.
/lead-magnets
local
When the user wants to create, plan, or optimize a lead magnet for email capture or lead generation. Also.
When: When the user wants to create, plan, or optimize a lead magnet for email capture or lead generation. Also.
/marketing-ideas
local
When the user needs marketing ideas, inspiration, or strategies for their SaaS or software product. Also.
When: When the user needs marketing ideas, inspiration, or strategies for their SaaS or software product. Also.
/marketing-psychology
local
When the user wants to apply psychological principles, mental models, or behavioral science to marketing. Also.
When: When the user wants to apply psychological principles, mental models, or behavioral science to marketing. Also.
/paid-ads
local
When the user wants help with paid advertising campaigns on Google Ads, Meta (Facebook/Instagram), LinkedIn, Twitter/X, or other ad platforms. Also.
When: When the user wants help with paid advertising campaigns on Google Ads, Meta (Facebook/Instagram), LinkedIn, Twitter/X, or other ad platforms. Also.
/pricing-strategy
local
When the user wants help with pricing decisions, packaging, or monetization strategy. Also.
When: When the user wants help with pricing decisions, packaging, or monetization strategy. Also.
/product-marketing-context
local
When the user wants to create or update their product marketing context document. Also.
When: When the user wants to create or update their product marketing context document. Also.
/referral-program
local
When the user wants to create, optimize, or analyze a referral program, affiliate program, or word-of-mouth strategy. Also.
When: When the user wants to create, optimize, or analyze a referral program, affiliate program, or word-of-mouth strategy. Also.
/revops
local
When the user wants help with revenue operations, lead lifecycle management, or marketing-to-sales handoff processes. Also.
When: When the user wants help with revenue operations, lead lifecycle management, or marketing-to-sales handoff processes. Also.
/sales-enablement
local
When the user wants to create sales collateral, pitch decks, one-pagers, objection handling docs, or demo scripts. Also.
When: When the user wants to create sales collateral, pitch decks, one-pagers, objection handling docs, or demo scripts. Also.
/social-content
local
When the user wants help creating, scheduling, or optimizing social media content for LinkedIn, Twitter/X, Instagram, TikTok, Facebook, or other platforms. Also.
When: When the user wants help creating, scheduling, or optimizing social media content for LinkedIn, Twitter/X, Instagram, TikTok, Facebook, or other platforms. Also.
Automation, AI & Technical
/aurea-clinic-outbound-enrichment
workspace
Prepare and enrich JCT Advisory cold clinic prospects for outbound calling.
When: Prepare and enrich JCT Advisory cold clinic prospects for outbound calling.
/cloudflare-deploy
local
Deploy applications and infrastructure to Cloudflare using Workers, Pages, and related platform services.
When: Deploy applications and infrastructure to Cloudflare using Workers, Pages, and related platform services.
/diagnose
local
Disciplined diagnosis loop for hard bugs and performance regressions. Reproduce → minimise → hypothesise → instrument → fix → regression-test.
When: Disciplined diagnosis loop for hard bugs and performance regressions. Reproduce → minimise → hypothesise → instrument → fix → regression-test.
/git-guardrails-claude-code
local
Set up Claude Code hooks to block dangerous git commands (push, reset --hard, clean, branch -D, etc.) before they execute.
When: Set up Claude Code hooks to block dangerous git commands (push, reset --hard, clean, branch -D, etc.) before they execute.
/hyperframes
local
Create video compositions, animations, title cards, overlays, captions, voiceovers, audio-reactive visuals, and scene transitions in HyperFrames HTML.
When: Create video compositions, animations, title cards, overlays, captions, voiceovers, audio-reactive visuals, and scene transitions in HyperFrames HTML.
/hyperframes-cli
local
HyperFrames CLI tool — hyperframes init, lint, inspect, preview, render, transcribe, tts, doctor, browser, info, upgrade, compositions, docs, benchmark.
When: HyperFrames CLI tool — hyperframes init, lint, inspect, preview, render, transcribe, tts, doctor, browser, info, upgrade, compositions, docs, benchmark.
/improve-codebase-architecture
local
Find deepening opportunities in a codebase, informed by the domain language in CONTEXT.md and the decisions in docs/adr/.
When: Find deepening opportunities in a codebase, informed by the domain language in CONTEXT.md and the decisions in docs/adr/.
/migrate-to-shoehorn
local
Migrate test files from `as` type assertions to @total-typescript/shoehorn.
When: Migrate test files from `as` type assertions to @total-typescript/shoehorn.
/n8n-code-javascript
system
Write JavaScript code in n8n Code nodes.
When: Write JavaScript code in n8n Code nodes.
/n8n-code-python
system
Write Python code in n8n Code nodes.
When: Write Python code in n8n Code nodes.
/n8n-expression-syntax
system
Validate n8n expression syntax and fix common errors.
When: Validate n8n expression syntax and fix common errors.
/n8n-mcp-tools-expert
system
Expert guide for using n8n-mcp MCP tools effectively.
When: Expert guide for using n8n-mcp MCP tools effectively.
/n8n-node-configuration
system
Operation-aware node configuration guidance.
When: Operation-aware node configuration guidance.
/n8n-validation-expert
system
Interpret validation errors and guide fixing them.
When: Interpret validation errors and guide fixing them.
/n8n-workflow-patterns
system
Proven workflow architectural patterns from real n8n workflows.
When: Proven workflow architectural patterns from real n8n workflows.
/pdf
local
Use for pdf workflows.
When:
/playwright
local
Use for playwright workflows.
When:
/playwright-interactive
local
Persistent browser and Electron interaction through `js_repl` for fast iterative UI debugging.
When: Persistent browser and Electron interaction through `js_repl` for fast iterative UI debugging.
/prototype
local
Build a throwaway prototype to flesh out a design before committing to it. Routes between two branches — a runnable terminal app for state/business-logic questions, or several radically...
When: Build a throwaway prototype to flesh out a design before committing to it. Routes between two branches — a runnable terminal app for state/business-logic questions, or several radically different UI variations...
/qmd
system
Bootstrap QMD search instructions from the installed qmd CLI.
When: Bootstrap QMD search instructions from the installed qmd CLI.
/security-review
local
When the user wants to audit a file or script for security vulnerabilities before shipping — credential exposure, unauthenticated endpoints, injection risks, insecure defaults. Trigger on...
When: When the user wants to audit a file or script for security vulnerabilities before shipping — credential exposure, unauthenticated endpoints, injection risks, insecure defaults. Trigger on "security review"...
/setup-pre-commit
local
Set up Husky pre-commit hooks with lint-staged (Prettier), type checking, and tests in the current repo.
When: Set up Husky pre-commit hooks with lint-staged (Prettier), type checking, and tests in the current repo.
/tdd
local
Test-driven development with red-green-refactor loop.
When: Test-driven development with red-green-refactor loop.
/vapi-prompt-builder
workspace
Build a production-quality VAPI AI assistant prompt from scratch. Use this skill whenever the user asks to write, rewrite, improve, or audit a VAPI assistant prompt — for outbound cold...
When: Build a production-quality VAPI AI assistant prompt from scratch. Use this skill whenever the user asks to write, rewrite, improve, or audit a VAPI assistant prompt — for outbound cold callers, inbound...
/website-to-hyperframes
local
|.
When: |.
Operations, Writing & Workflow
/caveman
local
>.
When: >.
/grill-me
local
Interview the user relentlessly about a plan or design until reaching shared understanding, resolving each branch of the decision tree.
When: Interview the user relentlessly about a plan or design until reaching shared understanding, resolving each branch of the decision tree.
/grill-with-docs
local
Grilling session that challenges your plan against the existing domain model, sharpens terminology, and updates documentation (CONTEXT.md, ADRs) inline as decisions crystallise.
When: Grilling session that challenges your plan against the existing domain model, sharpens terminology, and updates documentation (CONTEXT.md, ADRs) inline as decisions crystallise.
/handoff What will the next session be used for?
local
Compact the current conversation into a handoff document for another agent to pick up.
When: Compact the current conversation into a handoff document for another agent to pick up.
/obsidian-vault
local
Search, create, and manage notes in the Obsidian vault with wikilinks and index notes.
When: Search, create, and manage notes in the Obsidian vault with wikilinks and index notes.
/qa
local
Interactive QA session where user reports bugs or issues conversationally, and the agent files GitHub issues. Explores the codebase in the background for context and domain language.
When: Interactive QA session where user reports bugs or issues conversationally, and the agent files GitHub issues. Explores the codebase in the background for context and domain language.
/request-refactor-plan
local
Create a detailed refactor plan with tiny commits via user interview, then file it as a GitHub issue.
When: Create a detailed refactor plan with tiny commits via user interview, then file it as a GitHub issue.
/review
local
Review the changes since a fixed point (commit, branch, tag, or merge-base) along two axes — Standards (does the code follow this repo's documented coding standards?) and Spec (does the...
When: Review the changes since a fixed point (commit, branch, tag, or merge-base) along two axes — Standards (does the code follow this repo's documented coding standards?) and Spec (does the code match what the...
/scaffold-exercises
local
Create exercise directory structures with sections, problems, solutions, and explainers that pass linting.
When: Create exercise directory structures with sections, problems, solutions, and explainers that pass linting.
/screenshot
local
Use for screenshot workflows.
When:
/session-handoff
system
Use for session handoff workflows.
When:
/setup-matt-pocock-skills
local
Sets up an `## Agent skills` block in AGENTS.md/CLAUDE.md and `docs/agents/` so the engineering skills know this repo's issue tracker (GitHub or local markdown), triage label vocabulary...
When: Sets up an `## Agent skills` block in AGENTS.md/CLAUDE.md and `docs/agents/` so the engineering skills know this repo's issue tracker (GitHub or local markdown), triage label vocabulary, and domain doc layout...
/speckit-git-commit
system
Auto-commit changes after a Spec Kit command completes.
When: Auto-commit changes after a Spec Kit command completes.
/speckit-git-feature
system
Create a feature branch with sequential or timestamp numbering.
When: Create a feature branch with sequential or timestamp numbering.
/speckit-git-initialize
system
Initialize a Git repository with an initial commit.
When: Initialize a Git repository with an initial commit.
/speckit-git-remote
system
Detect Git remote URL for GitHub integration.
When: Detect Git remote URL for GitHub integration.
/speckit-git-validate
system
Validate current branch follows feature branch naming conventions.
When: Validate current branch follows feature branch naming conventions.
/teach What would you like to learn about?
local
Teach the user a new skill or concept, within this workspace.
When: Teach the user a new skill or concept, within this workspace.
/to-issues
local
Break a plan, spec, or PRD into independently-grabbable issues on the project issue tracker using tracer-bullet vertical slices.
When: Break a plan, spec, or PRD into independently-grabbable issues on the project issue tracker using tracer-bullet vertical slices.
/to-prd
local
Turn the current conversation context into a PRD and publish it to the project issue tracker.
When: Turn the current conversation context into a PRD and publish it to the project issue tracker.
/triage
local
Triage issues through a state machine driven by triage roles.
When: Triage issues through a state machine driven by triage roles.
/ubiquitous-language
local
Extract a DDD-style ubiquitous language glossary from the current conversation, flagging ambiguities and proposing canonical terms. Saves to UBIQUITOUS_LANGUAGE.md.
When: Extract a DDD-style ubiquitous language glossary from the current conversation, flagging ambiguities and proposing canonical terms. Saves to UBIQUITOUS_LANGUAGE.md.
/write-a-skill
local
Create new agent skills with proper structure, progressive disclosure, and bundled resources.
When: Create new agent skills with proper structure, progressive disclosure, and bundled resources.
/writing-beats
local
Shape an article as a journey of beats, choose-your-own-adventure style. The user picks a starting beat from the raw material, you write only that beat, then offer options for where to...
When: Shape an article as a journey of beats, choose-your-own-adventure style. The user picks a starting beat from the raw material, you write only that beat, then offer options for where to pivot next, beat by...
/writing-fragments
local
Grilling session that mines the user for fragments — heterogeneous nuggets of writing (claims, vignettes, sharp sentences, half-thoughts) — and appends them to a single document as raw...
When: Grilling session that mines the user for fragments — heterogeneous nuggets of writing (claims, vignettes, sharp sentences, half-thoughts) — and appends them to a single document as raw material for a future...
/writing-shape
local
Take a markdown file of raw material and shape it into an article through a conversational session — drafting candidate openings, growing the piece paragraph by paragraph, arguing about...
When: Take a markdown file of raw material and shape it into an article through a conversational session — drafting candidate openings, growing the piece paragraph by paragraph, arguing about format (lists, tables...
/zoom-out
local
Tell the agent to zoom out and give broader context or a higher-level perspective.
When: Tell the agent to zoom out and give broader context or a higher-level perspective.
All Source Documents
These are the source markdown files in docs/, docs/Doc Business/, and docs/Camille/. Edit them directly, then run python build.py and redeploy to update the site.
| Title | File | Updated | Read time | Description |
|---|---|---|---|---|
| AUREA COMMERCIAL GUIDE — v6 | docs/Aurea Growth V6.md | 2026-05-14 | 9 min read | Growth-Led Positioning, Offer Logic, Qualification, and GTM Doctrine |
| Deploy Mockup — Camille SOP | docs/Camille/deploy-mockup-sop.md | 2026-06-22 | 4 min read | Last updated: 2026-06-22 |
| Email To Camille — US Trades Prospecting Pack | docs/Camille/us-trades-prospecting-email-to-camille.md | 2026-06-06 | 2 min read | Subject: New US trades prospecting workflow — lead discovery + GHL push |
| Camille Pack — US Trades Lead Discovery + GHL Push | docs/Camille/us-trades-prospecting-pack.md | 2026-06-30 | 7 min read | Purpose: give Camille an independent weekly/monthly workflow to generate and push US trades prospects for the website-pivot offer, without asking John to run th |
| AI Content Assets Operating System | docs/Doc Business/ai-content-assets-operating-system.md | 2026-05-23 | 8 min read | This playbook captures the useful system from the "Alex Hormozi AI social media system" transcript. |
| AI Digital Product Questionnaire Playbook | docs/Doc Business/ai-digital-product-questionnaire-playbook.md | 2026-05-23 | 10 min read | This playbook captures the useful pattern from the "AI digital product using Base44" transcript. |
| AI Micro-App Vibe Coding Playbook | docs/Doc Business/ai-micro-app-vibe-coding-playbook.md | 2026-05-23 | 9 min read | This playbook captures the useful operating pattern from the "Claude Code builds a $400K/mo app" transcript. |
| AI One-Person Business Playbook | docs/Doc Business/ai-one-person-business-playbook.md | 2026-05-23 | 9 min read | This playbook captures the practical operating model from the "Claude as business operating system" transcript. |
| AI Website Agency Sales Playbook | docs/Doc Business/ai-website-agency-sales-playbook.md | 2026-06-21 | 41 min read | Reference playbook for building, selling, and scaling AI-assisted websites for local businesses. |
| Claude/Codex + CapCut + Remotion Best Practices | docs/Doc Business/claude-codex-capcut-remotion-best-practices.md | 2026-05-23 | 27 min read | Use this playbook when creating premium motion graphics, video overlays, animated UI elements, LUTs, SRT effects, raw-video edits, or reusable CapCut assets wit |
| Clinic Omnichannel AI Stack — Decision Playbook | docs/Doc Business/clinic-omnichannel-ai-stack-playbook.md | 2026-05-11 | 19 min read | Last updated: 2026-05-06 |
| Jordan Platten — Reference Strategy | docs/Doc Business/jordan-unfair-ai-cold-outreach-reference.md | 2026-06-14 | 14 min read | Document de reference dedie a la strategie exposee dans la video sur le systeme d'outreach AI capable de generer des rendez-vous de vente de maniere largement a |
| Agentic Architecture Upgrade Plan — 2026-03-28 | docs/agentic-architecture-upgrade-plan-2026-03-28.md | 2026-04-20 | 11 min read | > Added by Codex on 2026-03-28 for durable handoff to Claude Code / Cloud Code. Purpose: assess how to integrate external repos and patterns into the current JC |
| Aurea Ad Creative Context | docs/aurea-ad-creative-context.md | 2026-04-08 | 4 min read | System context for use with /ad-creative and /paid-ads skills. Feed this file when generating Meta ad briefs, Google Ads copy, or any paid creative for clinic c |
| Aurea Copywriting Context | docs/aurea-copywriting-context.md | 2026-06-14 | 4 min read | System context for use with the /copywriting skill. Feed this file when reviewing or writing any Aurea-facing copy — Mailman letters, GHL email templates, SMS f |
| Aurea Growth — Go-to-Market Strategy | docs/aurea-gtm.md | 2026-06-14 | 32 min read | > Last updated: 2026-06-06 |
| Aurea Growth — Meta Ad Copy (All 10 Videos) | docs/aurea-meta-ad-copy.md | 2026-03-30 | 14 min read | Campaign: Click-to-WhatsApp | Messaging objective | UK clinic owners |
| Aurea Growth — Meta Campaign Strategy | docs/aurea-meta-campaign-strategy.md | 2026-04-20 | 55 min read | > Status: Phase 1 Click-to-WhatsApp paused on 2026-03-29. Instant Form relaunch published on 2026-04-06, paused on 2026-04-09 for form correction, relaunched on |
| Aurea Post-Call Renderer Design | docs/aurea-post-call-renderer-design.md | 2026-04-20 | 6 min read | Last updated: 2026-04-04 |
| Aurea Recruitment Sourcing Reference | docs/aurea-recruitment-sourcing-reference-2026-04-16.md | 2026-05-02 | 12 min read | Last updated: 2026-05-02 |
| Aurea Growth — UGC Script Pack | docs/aurea-ugc-3-core-angles-instant-form.md | 2026-04-20 | 10 min read | > Status: working draft |
| Aurea Voice Agent Architecture: Clinic Prospecting | docs/aurea_voice_agent_architecture.md | 2026-04-20 | 8 min read | Last updated: 2026-04-02 |
| Business Demo Generator — Design System | docs/business-demo-generator-design-system.md | 2026-06-11 | 12 min read | > The goal is not to generate a template with their name on it. It is to rebuild a credible version of their actual business using their real assets, real revie |
| Claude Code / Codex / Connectors Best Practices | docs/claude-codex-agentic-best-practices.md | 2026-05-23 | 10 min read | Use this playbook when working with Claude Code, Codex, local files, QMD, Graphify, MCP/connectors, and cross-agent handoffs inside Aurea Growth. |
| David / Smile Wanted — Company-Only Target List | docs/david-smilewanted-consolidated-list-2026-04-16.md | 2026-04-16 | 4 min read | Date: 2026-04-16 |
| Field Growth Rep Interview Deck | docs/field-growth-rep-interview-deck-v1.md | 2026-04-20 | 6 min read | This deck is for interviewing and onboarding Field Growth Rep candidates for Aurea Growth. |
| Gemini Batch API Reference | docs/gemini-batch-api-reference.md | 2026-04-20 | 3 min read | Source: user-provided reference saved on 2026-03-29. |
| GHL Post-Call Renderer Workflow Blueprint | docs/ghl-post-call-renderer-workflow-blueprint.md | 2026-04-20 | 9 min read | Last updated: 2026-04-07 |
| GHL Voice Agent Knowledge Bases — JCT Advisory | docs/ghl-voice-agent-knowledge-bases-2026-04-14.md | 2026-04-14 | 3 min read | Last updated: 2026-04-14 |
| GHL Voice Agent Prompts + Knowledge Base — JCT Advisory | docs/ghl-voice-agent-prompts-2026-04-14.md | 2026-04-20 | 21 min read | Last updated: 2026-04-14 (post live number tests) |
| GHL Voice Agents Mapping — JCT Advisory | docs/ghl-voice-agents-mapping-2026-04-14.md | 2026-04-14 | 9 min read | Last updated: 2026-04-14 (post live number tests) |
| GoHighLevel Workflow Audit | docs/ghl-workflow-audit-2026-04-09.md | 2026-04-20 | 8 min read | Date: 2026-04-09 |
| Intelligence Graph — Full System SOP | docs/intelligence-graph-sop.md | 2026-07-01 | 18 min read | This is the canonical reference for the Oracle Intelligence Graph: a private, compounding knowledge base of every person and company John has a commercial or ca |
| JCT Advisory GHL Voice Audit — 2026-04-14 | docs/jct-advisory-ghl-voice-audit-2026-04-14.md | 2026-04-20 | 13 min read | Last updated: 2026-04-14 (after disposition confirmation and live number retest) |
| John Tossou — Independent Buyer-Side Advisory | docs/jct-advisory-one-pager.md | 2026-04-18 | 4 min read | For CMOs, founders, and commercial leaders making decisions they only get to make once. |
| JCT Advisory GHL ↔ Vapi Alignment Audit | docs/jct-ghl-vapi-alignment-audit-2026-04-04.md | 2026-04-20 | 8 min read | Date: 2026-04-04 |
| John Tossou — Personal Commercial GTM | docs/john-personal-gtm.md | 2026-06-14 | 4 min read | > Last updated: June 2026 |
| John Tossou - Master Experience Document | docs/john-tossou-master-experience.md | 2026-07-01 | 111 min read | Purpose: central source of truth for John's professional experience, metrics, clients, positioning angles, and CV-safe notes. This document is meant to consolid |
| johntossou-brand-strategy | docs/johntossou-brand-strategy.md | 2026-06-14 | 18 min read | name: johntossou.com — personal brand consulting vehicle |
| John Tossou — LinkedIn Profile Copy | docs/johntossou-linkedin.md | 2026-05-02 | 2 min read | Last updated: 2026-05-02 |
| JT Commercial Communication System | docs/jt-commercial-communication-system.md | 2026-07-03 | 7 min read | The competitive advantage is not copywriting. It is finding the commercial tension. The email is the output. |
| Mailman Visual Upgrade Log — 2026-03-28 | docs/mailman-visual-upgrade-log-2026-03-28.md | 2026-03-28 | 2 min read | - User asked to exploit the UI UX Pro Max repo ideas to improve the visual quality of Mailman letters before batching the week's outputs. |
| Meta UGC Hook Best Practices | docs/meta-ugc-hook-best-practices.md | 2026-04-20 | 14 min read | Date: 2026-04-03 |
| Norman Daliva - Candidate File | docs/norman-daliva-candidate-file.md | 2026-06-05 | 12 min read | Last updated: 2026-06-05 (role abandoned / replacement in progress) |
| Independent Contractor Agreement | docs/norman-daliva-cold-caller-contractor-agreement.md | 2026-05-06 | 11 min read | JCT Advisory Ltd trading as Aurea Growth - Cold Caller / Appointment Setter |
| Phone Number Architecture | docs/phone-number-architecture.md | 2026-04-20 | 6 min read | Last updated: 2026-04-14 |
| Pre-Ship Checklist | docs/pre-ship-checklist.md | 2026-04-08 | 1 min read | Run this before pushing any script change to production — Cloudflare Worker, Flask app, webhook receivers, or any tool that touches external APIs. |
| Private Intake Demo — Project Hub | docs/private-intake-demo.md | 2026-04-20 | 21 min read | Status: V1 complete (Aisha). Generator pipeline rebuilt with Claude Vision. Reliability hardening completed on 2026-04-02. Gemini visual-analysis experiments ad |
| Proposal Template Best Practices | docs/proposal-template-best-practices.md | 2026-04-20 | 7 min read | This document captures the best practices learned from building proposals for: |
| Site Build From Scratch: Dr Andrew Winter Aesthetics | docs/site-build-from-scratch-dr-winter-case-study.md | 2026-05-18 | 35 min read | Last updated: 2026-05-18 (Phase 9 — critique, performance, and premium motion pass) |
| Stop Vibe Coding. Start Getting Customers. — Reference Strategy | docs/stop-vibe-coding-start-getting-customers-reference.md | 2026-04-09 | 12 min read | Document de reference dedie a la these exposee dans cet episode sur la facon de transformer des projets AI "vibe coded" en business capables d'obtenir de vrais |
| Field Growth Rep — Candidate Brief | docs/street-team-candidate-brief.md | 2026-04-20 | 10 min read | You walk into target clinics, speak to the owner or clinic manager, show them something specific about their own booking flow, and book a short call with John. |
| Independent Contractor Agreement | docs/street-team-independent-contractor-template.md | 2026-04-20 | 6 min read | Aurea Growth - Street Team Operator |
| UGC AI Generation Best Practices | docs/ugc-ai-generation-best-practices-2026-03-29.md | 2026-04-20 | 9 min read | Date: 2026-03-29 |
| Universal Directory Setup | docs/universal-directory-setup.md | 2026-04-20 | 1 min read | This dashboard creates a single interactive HTML index for the full Aurea Growth root. |
| Upwork Brief — UGC Actors for Aurea Meta Campaign | docs/upwork-ugc-meta-actors-brief.md | 2026-04-20 | 4 min read | I am looking for UGC-style actors/creators to record short face-to-camera Meta ad creatives for an aesthetics-clinic campaign. |
| Vapi + GoHighLevel Best Practices | docs/vapi-ghl-best-practices-2026-03-31.md | 2026-05-04 | 29 min read | Plain-English reference for what we learned while testing Vapi with GoHighLevel / LeadConnector. |
| Aurea AI Outbound Routing System | docs/vapi-outbound-routing-system.md | 2026-05-26 | 45 min read | Last updated: 2026-05-26 |
| Voice Agent — Setup Guide | docs/voice-agent-guide.md | 2026-05-16 | 5 min read | Practical reference for building, configuring, and routing Vapi voice agents to GoHighLevel. Production-validated from live outbound calling sessions. |
| Aurea Growth SOP — Building Websites & Landing Pages with Codex/Claude Code, GHL Logic, and External Hosting | docs/website-landing-page-ghl-external-hosting-sop.md | 2026-05-15 | 35 min read | Last updated: 2026-05-13 (revised 2026-05-15: added smart-quote HTML attribute bug to Section 7 and Technical QA; revised 2026-05-13: added GHL iframe performan |