@elitedcs/ghl-mcp 3.53.2 → 3.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +62 -32
- package/README.md +9 -7
- package/dist/index.js +1922 -684
- package/package.json +4 -3
- package/skills/blueprint/README.md +27 -0
- package/skills/blueprint/SKILL.md +149 -0
- package/skills/blueprint/examples/medspa-approval-view.md +92 -0
- package/skills/blueprint/examples/medspa-brief.json +52 -0
- package/skills/blueprint/examples/medspa-build-plan.json +265 -0
- package/skills/blueprint/examples/medspa-dry-run-report.md +67 -0
- package/skills/blueprint/examples/sample-approval-view.md +82 -0
- package/skills/blueprint/examples/sample-brief.json +13 -0
- package/skills/blueprint/examples/sample-build-plan.json +227 -0
- package/skills/blueprint/examples/validate-plan.cjs +127 -0
- package/skills/blueprint/presets/clinic-launch-a2p.md +39 -0
- package/skills/blueprint/presets/clinic-launch-a2p.preset.json +337 -0
- package/skills/blueprint/presets/generic-client.md +36 -0
- package/skills/blueprint/presets/generic-client.preset.json +255 -0
- package/skills/blueprint/presets/med-spa.md +59 -0
- package/skills/blueprint/presets/med-spa.preset.json +264 -0
- package/skills/blueprint/references/agency-os-detection.md +80 -0
- package/skills/blueprint/references/approval-view.md +83 -0
- package/skills/blueprint/references/brief-schema.md +45 -0
- package/skills/blueprint/references/build-plan-schema.md +52 -0
- package/skills/blueprint/references/external-funnel.md +310 -0
- package/skills/blueprint/references/intake-question-set.md +141 -0
- package/skills/blueprint/references/preset-format.md +130 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Intake Question Set — v1.1 (hand-off to ghl-command-mcp)
|
|
2
|
+
|
|
3
|
+
STATUS: FINAL for v1.1, 2026-06-15. Owner: atlas (wording/labels) → ghl-command-mcp (builds the form-template installer from this). Jerry approves the final set. **v1.1 adds 3 keys** (`team_size`, `monthly_lead_volume`, `business_hours`) per Jerry's 2026-06-15 ruling — see "Ratified additions" at the bottom.
|
|
4
|
+
|
|
5
|
+
This is the canonical list of questions the installed intake form asks. It is the **built-in fallback brief source** (schema §2A path B) — the path taken when no partner OS (Agency OS) is detected or the subscriber declines it. It is the FLOOR: the form is installed regardless, because it is the only path when no partner OS is present.
|
|
6
|
+
|
|
7
|
+
**Contract rule honored:** the 25 original `key`s below are unchanged from schema §3 (changing a key is a contract change). Only wording/labels/options/help text are finalized here. **3 keys were ADDED** (`team_size`, `monthly_lead_volume`, `business_hours`) per Jerry's 2026-06-15 ruling — a coordinated contract change: command-center folds them into schema §3 + §6, ghl-command-mcp adds them to the installer. They are integrated into the sections below (Section A: A6–A8) and the Key → Brief map; the atlas-owned dataType + brief-path decisions are documented under "Ratified additions" at the bottom.
|
|
8
|
+
|
|
9
|
+
Each question maps 1:1 to a Brief field (schema §4) via its `key`. The mapping column is authoritative for the normalizer.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## How the installer should read this
|
|
14
|
+
|
|
15
|
+
- The form is **account-agnostic**: installed into whatever `get_current_location` returns, zero hardcoded IDs.
|
|
16
|
+
- The form needs the **standard GHL contact fields** too (first name, last name, email, phone) — these carry the submitter/contact identity and are not business-profile `key`s. They are not in the table below; add them as the form's standard contact block. The business-profile answers below populate the Brief.
|
|
17
|
+
- `required: true` questions are the minimum to generate a usable plan. Everything else is optional; the skill omits unknowns (never emits `null`) and notes safe defaults.
|
|
18
|
+
- Field types use GHL form field types. Where a question offers fixed choices, the options are listed verbatim; the installer should use these exact option labels (the normalizer matches on them).
|
|
19
|
+
- Sections A–F are display groupings (use as form sections/page breaks); they are not part of the contract.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Section A — Business basics
|
|
24
|
+
|
|
25
|
+
| # | Label (client sees) | `key` | Type | Required | Options / help |
|
|
26
|
+
|---|---|---|---|---|---|
|
|
27
|
+
| A1 | Business name | `business_name` | text | yes | Your business or brand name, as you want it to appear. |
|
|
28
|
+
| A2 | What kind of business is this? | `business_type` | dropdown | yes | Options: `Med spa`, `Clinic / practice`, `Coach / consultant`, `Ecommerce`, `Local service`, `Agency`, `Other`. *(Drives preset selection.)* |
|
|
29
|
+
| A3 | Website | `website` | url | no | If you have one. Leave blank if not. |
|
|
30
|
+
| A4 | Primary location | `primary_location` | text | no | City, State/Country. Used for tone + scheduling. |
|
|
31
|
+
| A5 | Time zone | `timezone` | dropdown | yes | Standard IANA time-zone list (e.g. `America/Phoenix`). Drives appointment hours and send windows. |
|
|
32
|
+
| A6 | How many people work your leads? | `team_size` | dropdown | no | Options: `Just me`, `2-5`, `6+`. Sizes how much human follow-up vs automation we build (and opportunity assignment / round-robin). |
|
|
33
|
+
| A7 | Roughly how many new leads per month? | `monthly_lead_volume` | dropdown | no | Options: `Under 100`, `100-500`, `500-1000`, `1000+`. Sizes SMS phone numbers (~1 per 500/mo) and send volume. Leave blank if unsure. |
|
|
34
|
+
| A8 | Your business hours | `business_hours` | textarea | no | e.g. "Mon-Fri 9-6, Sat 10-2". Sets your calendar's default booking hours. Leave blank for Mon-Fri 9-5. |
|
|
35
|
+
|
|
36
|
+
## Section B — Offer and pricing
|
|
37
|
+
|
|
38
|
+
| # | Label | `key` | Type | Required | Options / help |
|
|
39
|
+
|---|---|---|---|---|---|
|
|
40
|
+
| B1 | What do you sell? | `core_offer` | textarea | yes | One or two sentences. The main thing a customer buys from you. |
|
|
41
|
+
| B2 | Your main offers and prices | `price_points` | textarea | no | List your key offers with prices, one per line (e.g. "New client consult — $19"). |
|
|
42
|
+
| B3 | Free offer / lead magnet | `lead_magnet` | text | no | A free thing you give to capture a lead (assessment, guide, trial). Leave blank if none. |
|
|
43
|
+
| B4 | Average sale value | `avg_deal_value` | text | no | Roughly what a new customer is worth on the first purchase. |
|
|
44
|
+
|
|
45
|
+
## Section C — Audience
|
|
46
|
+
|
|
47
|
+
| # | Label | `key` | Type | Required | Options / help |
|
|
48
|
+
|---|---|---|---|---|---|
|
|
49
|
+
| C1 | Who is your ideal customer? | `ideal_customer` | textarea | yes | Who you serve best. Be specific (age, situation, what they want). |
|
|
50
|
+
| C2 | What problems do they come to you with? | `top_pain_points` | textarea | no | The top pains/frustrations that bring them in. One per line is fine. |
|
|
51
|
+
| C3 | Why do prospects hesitate? | `objections` | textarea | no | The objections you hear most (price, trust, timing, fear). |
|
|
52
|
+
|
|
53
|
+
## Section D — Goal and sales process
|
|
54
|
+
|
|
55
|
+
| # | Label | `key` | Type | Required | Options / help |
|
|
56
|
+
|---|---|---|---|---|---|
|
|
57
|
+
| D1 | What should this account do first and best? | `primary_goal` | dropdown | yes | Options: `Book appointments`, `Capture + nurture leads`, `Direct sales`, `Re-engage past clients`, `Other`. *(Drives the workflow + pipeline spine.)* |
|
|
58
|
+
| D2 | The steps a lead moves through, from new to won | `sales_stages` | textarea | no | Name the stages in order (e.g. "new lead → contacted → consult booked → showed → sold → repeat"). If blank, we use a sensible default for your business type. *(Drives pipeline stages.)* |
|
|
59
|
+
| D3 | Do customers book appointments with you? | `booking_needed` | radio (yes/no) | yes | Yes if you take consults/appointments. *(Drives whether a calendar is built.)* |
|
|
60
|
+
| D4 | Follow-up style | `follow_up_style` | dropdown | no | Options: `High-touch / multi-step`, `Light`, `Single confirmation`. How aggressively to follow up. |
|
|
61
|
+
|
|
62
|
+
## Section E — Channels and tech
|
|
63
|
+
|
|
64
|
+
| # | Label | `key` | Type | Required | Options / help |
|
|
65
|
+
|---|---|---|---|---|---|
|
|
66
|
+
| E1 | Is your business email sending set up? | `email_ready` | radio (yes/no) | no | Yes if you have a sending domain / mailbox connected in GHL. |
|
|
67
|
+
| E2 | Do you want to send text messages (SMS)? | `sms_desired` | radio (yes/no) | no | Yes flags the A2P registration step you'll need to complete. |
|
|
68
|
+
| E3 | A2P / SMS registration status | `a2p_status` | dropdown | no | Options: `Not started`, `In progress`, `Approved`, `Not needed`. |
|
|
69
|
+
| E4 | Payment processing | `payment_processor` | dropdown | no | Options: `Stripe connected`, `Stripe not connected`, `Other`, `None`. *(Flags the Stripe handoff if you sell on a page.)* |
|
|
70
|
+
| E5 | Is your calendar connected? | `calendar_connected` | radio (yes/no) | no | Yes if your Google/Outlook calendar is already authorized in GHL. *(Flags the OAuth handoff if booking is needed and this is no.)* |
|
|
71
|
+
| E6 | Which channels do you post on? | `social_channels` | multiselect | no | Options: `Instagram`, `Facebook`, `TikTok`, `YouTube`, `LinkedIn`, `Google Business`, `None`. |
|
|
72
|
+
|
|
73
|
+
## Section F — Assets on hand
|
|
74
|
+
|
|
75
|
+
| # | Label | `key` | Type | Required | Options / help |
|
|
76
|
+
|---|---|---|---|---|---|
|
|
77
|
+
| F1 | Do you already have a pipeline built? | `existing_pipeline` | radio (yes/no) + textarea | no | If yes, describe it briefly so we don't duplicate it. |
|
|
78
|
+
| F2 | Anything already built we should not touch? | `existing_workflows` | textarea | no | List workflows/automations already live that we must leave alone. *(Becomes the do-not-clobber guardrail for the executor.)* |
|
|
79
|
+
| F3 | Brand assets | `brand_assets` | text | no | Logo, colors, domain available — whatever you have. |
|
|
80
|
+
| F4 | Anything else we should know? | `anything_else` | textarea | no | Constraints, compliance limits, preferences, context. |
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Key → Brief field map (authoritative for the normalizer)
|
|
85
|
+
|
|
86
|
+
| `key` | Brief field (§4) |
|
|
87
|
+
|---|---|
|
|
88
|
+
| `business_name` | `business.name` |
|
|
89
|
+
| `business_type` | `business.type` + `preset` (selection) |
|
|
90
|
+
| `website` | `business.website` |
|
|
91
|
+
| `primary_location` | `business.location` |
|
|
92
|
+
| `timezone` | `business.timezone` |
|
|
93
|
+
| `team_size` | `business.teamSize` (enum) |
|
|
94
|
+
| `monthly_lead_volume` | `business.monthlyLeadVolume` (enum) |
|
|
95
|
+
| `business_hours` | `business.hours` |
|
|
96
|
+
| `core_offer` | `offer.summary` |
|
|
97
|
+
| `price_points` | `offer.pricePoints` (parse `[{name, price}]` per line) |
|
|
98
|
+
| `lead_magnet` | `offer.leadMagnet` |
|
|
99
|
+
| `avg_deal_value` | `offer.avgDealValue` |
|
|
100
|
+
| `ideal_customer` | `audience.ideal` |
|
|
101
|
+
| `top_pain_points` | `audience.painPoints` (split lines → array) |
|
|
102
|
+
| `objections` | `audience.objections` (split lines → array) |
|
|
103
|
+
| `primary_goal` | `goal.primary` |
|
|
104
|
+
| `sales_stages` | `goal.salesStages` (split → array of stage names) |
|
|
105
|
+
| `booking_needed` | `goal.bookingNeeded` (bool) |
|
|
106
|
+
| `follow_up_style` | `goal.followUpStyle` |
|
|
107
|
+
| `email_ready` | `channels.email` (bool) |
|
|
108
|
+
| `sms_desired` | `channels.sms` (bool) |
|
|
109
|
+
| `a2p_status` | `channels.a2pStatus` |
|
|
110
|
+
| `payment_processor` | `channels.payment` |
|
|
111
|
+
| `calendar_connected` | `channels.calendarConnected` (bool) |
|
|
112
|
+
| `social_channels` | `channels.social` (array) |
|
|
113
|
+
| `existing_pipeline` | `assets.existingPipeline` |
|
|
114
|
+
| `existing_workflows` | `assets.existingWorkflows` |
|
|
115
|
+
| `brand_assets` | `assets.brand` |
|
|
116
|
+
| `anything_else` | `assets.notes` |
|
|
117
|
+
|
|
118
|
+
### Derived `flags` (normalizer computes, not asked)
|
|
119
|
+
- `needs_a2p` ← `sms_desired == yes` AND `a2p_status != approved`
|
|
120
|
+
- `stripe_not_connected` ← `payment_processor == "Stripe not connected"`
|
|
121
|
+
- `calendar_oauth_needed` ← `booking_needed == yes` AND `calendar_connected == no`
|
|
122
|
+
- `email_domain_needed` ← `email_ready == no`
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Ratified additions — folded in 2026-06-15 (Jerry)
|
|
127
|
+
|
|
128
|
+
These three keys came up while reconciling against the CLL 49-field form and Module 0 prereqs. **Jerry ratified adding all three on 2026-06-15** (`outbox/2026-06-15-to-atlas-intake-decisions.md`, decision #1, overriding the earlier "ship without"). They are now in the installed set above (Section A: A6–A8) and the Key → Brief map. Adding them is a coordinated contract change: **command-center** folds the keys into schema §3 + §6; **ghl-command-mcp** adds them to the form-template installer. All three are **optional** (the required floor is unchanged), so the skill still degrades gracefully when a subscriber leaves them blank.
|
|
129
|
+
|
|
130
|
+
atlas-owned wording decisions — the dataType + brief path proposed for cc (§3/§6 fold-in) and mcp (installer):
|
|
131
|
+
|
|
132
|
+
| `key` | Form type | GHL `dataType` | Brief path (§4) | Brief type | Option labels | Drives in plan |
|
|
133
|
+
|---|---|---|---|---|---|---|
|
|
134
|
+
| `team_size` | dropdown | `SINGLE_OPTIONS` | `business.teamSize` | enum | `Just me`, `2-5`, `6+` | speed-to-lead human-follow-up sizing + opportunity assignment / round-robin; calendar staff hint |
|
|
135
|
+
| `monthly_lead_volume` | dropdown | `SINGLE_OPTIONS` | `business.monthlyLeadVolume` | enum | `Under 100`, `100-500`, `500-1000`, `1000+` | SMS phone-number count for the clinic_launch_a2p preset (~1 per 500/mo) + send-volume sizing |
|
|
136
|
+
| `business_hours` | textarea | `LARGE_TEXT` | `business.hours` | string | — (free text) | calendar `openHours` defaults (replaces the generic Mon-Fri 9-5); parsed + operator-editable |
|
|
137
|
+
|
|
138
|
+
Fold-in notes:
|
|
139
|
+
- **`monthly_lead_volume` refined from the original "(text)" proposal → dropdown buckets (`SINGLE_OPTIONS`).** Free text ("a few hundred?") is unparseable for the 1-number-per-500 math; fixed buckets map cleanly to a phone-number count. Flagging the type change explicitly so the installer builds a dropdown, not a text field.
|
|
140
|
+
- All three land under the Brief's `business.*` namespace (new sub-keys `teamSize`, `monthlyLeadVolume`, `hours`) — purely additive, no existing field changes, so `schemaVersion` stays `0.1`.
|
|
141
|
+
- No new derived `flags`. `monthly_lead_volume` is read directly by the clinic_launch_a2p preset at phone-provisioning time; absent → the preset keeps its current ask-at-handoff default. `business_hours` absent → skill keeps the Mon-Fri 9-5 default + operator-edit flag. `team_size` absent → skill keeps "automate first touch, human follow-up light."
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Preset Format & Versioning
|
|
2
|
+
|
|
3
|
+
STATUS: v1, 2026-06-15. Owner: atlas. Defines how Intake-to-Build presets are authored, versioned, and consumed by the plan-gen skill. Ratifies schema §7 item 4 (preset → plan determinism).
|
|
4
|
+
|
|
5
|
+
## What a preset is
|
|
6
|
+
|
|
7
|
+
A preset is a **build-plan template**: it is authored in the exact vocabulary of the §5 build-plan (refs, logical actions, handoffs), with two additions — **template tokens** that the skill fills from the brief, and **`conditionalOn`** flags that the skill evaluates to add or drop items. The preset sets the *skeleton*; the brief fills the *specifics*.
|
|
8
|
+
|
|
9
|
+
This keeps preset → plan **deterministic** and keeps the preset in the same shape the operator reviews and the phase-2 executor consumes. There is no separate "preset language" to learn beyond §5 + the two additions below.
|
|
10
|
+
|
|
11
|
+
> Ratification of §7 #4: **the preset fixes the skeleton** (pipeline stage *set*, the workflow *set*, the asset *list*, the handoff *set*, default copy direction). **The brief fills** names, copy, toggles, and any list the brief overrides (e.g. stages from `goal.salesStages`). **Brief `flags` add or drop conditional items.** The skill does not invent structure the preset does not declare; it only fills, drops, and expands. Same brief + same preset version → same plan skeleton, every time.
|
|
12
|
+
|
|
13
|
+
## File layout
|
|
14
|
+
|
|
15
|
+
Each preset is two files in `intake-to-build/presets/`:
|
|
16
|
+
|
|
17
|
+
- `<preset-id>.preset.json` — the machine-readable template the skill loads.
|
|
18
|
+
- `<preset-id>.md` — a human companion: what this preset builds, when it is selected, and the source it was harvested from. (Reviewers read this; the skill reads the JSON.)
|
|
19
|
+
|
|
20
|
+
## Preset JSON envelope
|
|
21
|
+
|
|
22
|
+
```jsonc
|
|
23
|
+
{
|
|
24
|
+
"presetId": "med_spa",
|
|
25
|
+
"presetVersion": "1.0.0", // semver; bump on any skeleton change
|
|
26
|
+
"schemaVersion": "0.1", // the build-plan schema this targets
|
|
27
|
+
"title": "Med Spa",
|
|
28
|
+
"description": "One-line summary.",
|
|
29
|
+
"default": true, // exactly one preset across the library is the default
|
|
30
|
+
"selectors": { // how the skill picks this preset
|
|
31
|
+
"businessTypes": ["Med spa","Medical spa","Medical aesthetics","Aesthetics"],
|
|
32
|
+
"aliases": ["med_spa","medspa","medical_spa","aesthetics","injectables"]
|
|
33
|
+
},
|
|
34
|
+
"source": "ghl-command showcase Modules 0-7 + proven Bliss / Lux Bio med-spa builds",
|
|
35
|
+
"skeleton": { /* §5 build-plan shape with tokens + conditionalOn, see below */ }
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`selectors.businessTypes` are the `business_type` answers that route to this preset. `selectors.aliases` are the `brief.preset` enum values that resolve to this preset (e.g. `preset: "med_spa"` resolves to the med-spa preset, which claims that alias). Exactly one preset across the library has `"default": true` — currently **`med_spa`** (the reference preset). `generic` is `default:false`, the neutral fallback reached via its `businessTypes`.
|
|
40
|
+
|
|
41
|
+
## The `skeleton` object
|
|
42
|
+
|
|
43
|
+
`skeleton` mirrors the §5 build-plan top level — `pipelines`, `customFields`, `tags`, `customValues`, `calendars`, `forms`, `funnels`, `emails`, `sms`, `workflows`, `handoffs`. Every item is a §5 object, optionally annotated with:
|
|
44
|
+
|
|
45
|
+
### 1. Template tokens — `{{ ... }}`
|
|
46
|
+
A `{{path}}` inside any string field is replaced with the brief value at that path. Dotted paths read the brief (`{{business.name}}`, `{{offer.summary}}`). Supports a fallback with `||`:
|
|
47
|
+
|
|
48
|
+
```jsonc
|
|
49
|
+
{ "ref": "pipeline.main", "name": "{{business.name}} Pipeline || Patient Journey" }
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
If `business.name` is present, it fills; otherwise the literal after `||` is used. A token that resolves to empty with no fallback → the skill omits the field (never emits an empty string) and notes the default it used.
|
|
53
|
+
|
|
54
|
+
### 2. `conditionalOn` — include/drop the whole item
|
|
55
|
+
A string boolean expression over the brief. If it evaluates false, the skill **drops the item entirely** (and anything that referenced it — the skill prunes dangling refs and records the prune in the plan summary). Grammar is intentionally tiny:
|
|
56
|
+
|
|
57
|
+
- `goal.bookingNeeded == true`
|
|
58
|
+
- `channels.sms == true`
|
|
59
|
+
- `flags includes needs_a2p`
|
|
60
|
+
- `channels.payment != "Stripe connected"`
|
|
61
|
+
- combine with `&&` / `||`
|
|
62
|
+
|
|
63
|
+
```jsonc
|
|
64
|
+
{ "ref": "calendar.consult", "conditionalOn": "goal.bookingNeeded == true", "name": "Consultation", ... }
|
|
65
|
+
{ "ref": "handoff.a2p", "conditionalOn": "flags includes needs_a2p", ... }
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 3. `fillFrom` — populate a list from the brief, else the preset default
|
|
69
|
+
For list-valued structure the brief can override (the clearest case is pipeline stages):
|
|
70
|
+
|
|
71
|
+
```jsonc
|
|
72
|
+
{
|
|
73
|
+
"ref": "pipeline.main",
|
|
74
|
+
"name": "{{business.name}} Pipeline || Sales Pipeline",
|
|
75
|
+
"stages": {
|
|
76
|
+
"fillFrom": "goal.salesStages",
|
|
77
|
+
"transform": "stageList", // skill turns ["new lead","contacted",...] into [{ref,name,position}]
|
|
78
|
+
"default": [
|
|
79
|
+
{ "ref": "stage.new_lead", "name": "New Lead", "position": 0 },
|
|
80
|
+
{ "ref": "stage.contacted", "name": "Contacted", "position": 1 }
|
|
81
|
+
/* ... preset's own default stage set ... */
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
If `goal.salesStages` is non-empty, the skill builds the stage list from it (slugging each name into a `stage.<slug>` ref, assigning positions in order). If empty, it uses `default`. Workflows that point at `stage.*` refs resolve against whichever set won; if a referenced stage is not in the chosen set, the skill maps it to the nearest equivalent or notes the gap (it never ships a dead ref).
|
|
88
|
+
|
|
89
|
+
### 4. `copyDirection` — outline guidance for copy assets
|
|
90
|
+
On `emails`/`sms`/`funnels[].pages`, `copyDirection` is the instruction the skill turns into a `bodyOutline` (default) or full copy (on expansion — see RATIFICATION §3). Tokens and brief context (offer, audience, and `extended` ICA/offer/voice when partner-OS-sourced) ground the copy.
|
|
91
|
+
|
|
92
|
+
```jsonc
|
|
93
|
+
{ "ref": "email.welcome_1", "name": "Welcome 1",
|
|
94
|
+
"subject": "Welcome to {{business.name}}",
|
|
95
|
+
"copyDirection": "Thank them for reaching out; restate the core offer in their language; set expectation for next step; CTA to book. Warm, concrete, no hype.",
|
|
96
|
+
"mergeTags": ["contact.first_name"] }
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## The skill's deterministic fill algorithm (consumes a preset)
|
|
100
|
+
|
|
101
|
+
1. Resolve preset (brief.preset alias → preset, else business_type → preset, else default).
|
|
102
|
+
2. Deep-copy `skeleton`.
|
|
103
|
+
3. Evaluate every `conditionalOn`; drop false items; prune now-dangling refs (record prunes).
|
|
104
|
+
4. Resolve every `fillFrom` (brief override or default), slug refs, assign positions.
|
|
105
|
+
5. Substitute every `{{token}}` (with `||` fallback); omit-and-note where empty.
|
|
106
|
+
6. Derive flag-driven handoffs not already present (a2p, stripe, calendar_oauth, add_staff, email_domain).
|
|
107
|
+
7. Turn each `copyDirection` into a `bodyOutline` (or full copy on expansion).
|
|
108
|
+
8. Set `buildOrder`, compute `summary`, leave `idMap` empty.
|
|
109
|
+
9. Run the quality gate (SKILL.md), fix, then render the §5A approval view.
|
|
110
|
+
|
|
111
|
+
Steps 2–6 are pure and order-independent of the model's discretion — that is what makes the skeleton deterministic. Step 7 (copy) is the only generative step, and it is grounded in the brief, gated, and editable at review.
|
|
112
|
+
|
|
113
|
+
## Enum discipline (must pass the mcp validators)
|
|
114
|
+
|
|
115
|
+
Presets must use GHL-correct enum values so the emitted plan passes ghl-command-mcp's Zod / JSON-Schema validators (their §7 #1 ratification):
|
|
116
|
+
|
|
117
|
+
- `customFields[].dataType` ∈ `TEXT`, `LARGE_TEXT`, `NUMERICAL`, `PHONE`, **`MONETORY`** (GHL's own spelling — NOT "MONETARY"), `CHECKBOX`, `SINGLE_OPTIONS`, `MULTIPLE_OPTIONS`, `FLOAT`, `DATE`, `TEXTBOX_LIST`, `FILE_UPLOAD`, `SIGNATURE`. Choice types (`SINGLE_OPTIONS`/`MULTIPLE_OPTIONS`/`CHECKBOX`) MUST carry an `options` array.
|
|
118
|
+
- `calendars[].calendarType` ∈ `round_robin`, `event`, `class_booking`, `collective`, `service_booking`.
|
|
119
|
+
- `customFields[].model` ∈ `contact`, `opportunity`.
|
|
120
|
+
- **Trigger `type`** ∈ the executor's native set so triggers auto-build: `contact_tag`, `form_submission`, `appointment` (+ `appointmentStatus`), `customer_reply`, `pipeline_stage_updated`, `inbound_webhook`, `payment_received`. `form_submitted`/`contact_replied` are accepted aliases; `tag_added`/`appointment_status`/`appointment_booked` are NOT recognized (they surface as a manual step) — never use them in a preset.
|
|
121
|
+
- handoff `owner` ∈ **`OPERATOR-UI`**, **`OPERATOR-EXT`**, **`TEAM`** (customer-facing, generic). The MCP still accepts + normalizes the legacy `JERRY-UI`/`JERRY-EXT`/`SASHA`, but presets EMIT the canonical labels.
|
|
122
|
+
- `internal_notification.to` carries the `{{operator.userId}}` token (the skill resolves a real GHL user id from `get_users` at fill time — a non-user value is an unpublishable notify-all).
|
|
123
|
+
|
|
124
|
+
> The schema §5 contract (v0.3) and the live Zod schema (`src/intake-to-build/plan.ts`) are the sources of truth; the `MONETARY`/`MONETORY` spelling note is RESOLVED (the contract example was corrected in §7 #1). If the doc and the Zod schema ever disagree, the Zod schema wins.
|
|
125
|
+
|
|
126
|
+
## Versioning & distribution
|
|
127
|
+
|
|
128
|
+
- **Version:** semver in `presetVersion`. Patch = copy/wording; minor = additive items; major = removed/renamed refs or changed skeleton shape. The generated plan records which preset+version produced it in its `summary` line so a build is reproducible.
|
|
129
|
+
- **Distribution:** presets ship **alongside the skill** (the `intake-to-build/presets/` directory travels with `SKILL.md` in whatever package distributes the skill — the same mechanism, TBD, that distributes the Founder Operating Pack). They are not in the MCP package; the MCP consumes the *plan*, not the preset. Adding a preset = drop two files in `presets/` and give it a `selector`; no skill code change.
|
|
130
|
+
- **Authoring a new preset:** copy `generic-client.preset.json`, change `presetId`/`title`/`selectors`/`default:false`, edit the skeleton, write the `.md` companion. The skill picks it up by selector.
|