@sellable/mcp 0.1.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.
Files changed (200) hide show
  1. package/.claude-plugin/plugin.json +12 -0
  2. package/.mcp.json +9 -0
  3. package/README.md +355 -0
  4. package/dist/api.d.ts +21 -0
  5. package/dist/api.js +73 -0
  6. package/dist/auth.d.ts +60 -0
  7. package/dist/auth.js +246 -0
  8. package/dist/engage-memory.d.ts +63 -0
  9. package/dist/engage-memory.js +354 -0
  10. package/dist/index-dev.d.ts +2 -0
  11. package/dist/index-dev.js +17 -0
  12. package/dist/index.d.ts +7 -0
  13. package/dist/index.js +8 -0
  14. package/dist/server.d.ts +1 -0
  15. package/dist/server.js +499 -0
  16. package/dist/skills.d.ts +11 -0
  17. package/dist/skills.js +97 -0
  18. package/dist/tools/auth.d.ts +30 -0
  19. package/dist/tools/auth.js +124 -0
  20. package/dist/tools/blueprint-commit.d.ts +174 -0
  21. package/dist/tools/blueprint-commit.js +286 -0
  22. package/dist/tools/bootstrap.d.ts +64 -0
  23. package/dist/tools/bootstrap.js +246 -0
  24. package/dist/tools/campaigns.d.ts +589 -0
  25. package/dist/tools/campaigns.js +892 -0
  26. package/dist/tools/cells.d.ts +58 -0
  27. package/dist/tools/cells.js +48 -0
  28. package/dist/tools/context.d.ts +88 -0
  29. package/dist/tools/context.js +271 -0
  30. package/dist/tools/csv-domains.d.ts +73 -0
  31. package/dist/tools/csv-domains.js +464 -0
  32. package/dist/tools/csv-linkedin.d.ts +102 -0
  33. package/dist/tools/csv-linkedin.js +712 -0
  34. package/dist/tools/direct-campaigns.d.ts +240 -0
  35. package/dist/tools/direct-campaigns.js +250 -0
  36. package/dist/tools/engage-bootstrap.d.ts +94 -0
  37. package/dist/tools/engage-bootstrap.js +205 -0
  38. package/dist/tools/engage-discovery.d.ts +78 -0
  39. package/dist/tools/engage-discovery.js +150 -0
  40. package/dist/tools/engage-memory.d.ts +181 -0
  41. package/dist/tools/engage-memory.js +143 -0
  42. package/dist/tools/engage-state.d.ts +72 -0
  43. package/dist/tools/engage-state.js +62 -0
  44. package/dist/tools/enrichment.d.ts +167 -0
  45. package/dist/tools/enrichment.js +174 -0
  46. package/dist/tools/flow-preflight.d.ts +68 -0
  47. package/dist/tools/flow-preflight.js +138 -0
  48. package/dist/tools/framework.d.ts +44 -0
  49. package/dist/tools/framework.js +153 -0
  50. package/dist/tools/interaction-mode.d.ts +27 -0
  51. package/dist/tools/interaction-mode.js +102 -0
  52. package/dist/tools/leads.d.ts +2417 -0
  53. package/dist/tools/leads.js +2307 -0
  54. package/dist/tools/linkedin.d.ts +210 -0
  55. package/dist/tools/linkedin.js +229 -0
  56. package/dist/tools/navigation.d.ts +91 -0
  57. package/dist/tools/navigation.js +381 -0
  58. package/dist/tools/one-off.d.ts +229 -0
  59. package/dist/tools/one-off.js +273 -0
  60. package/dist/tools/processing.d.ts +70 -0
  61. package/dist/tools/processing.js +56 -0
  62. package/dist/tools/prompts.d.ts +211 -0
  63. package/dist/tools/prompts.js +210 -0
  64. package/dist/tools/provider-preflight.d.ts +21 -0
  65. package/dist/tools/provider-preflight.js +59 -0
  66. package/dist/tools/readiness.d.ts +261 -0
  67. package/dist/tools/readiness.js +510 -0
  68. package/dist/tools/rows.d.ts +126 -0
  69. package/dist/tools/rows.js +105 -0
  70. package/dist/tools/rubrics.d.ts +497 -0
  71. package/dist/tools/rubrics.js +681 -0
  72. package/dist/tools/senders.d.ts +44 -0
  73. package/dist/tools/senders.js +69 -0
  74. package/dist/tools/sequencer.d.ts +127 -0
  75. package/dist/tools/sequencer.js +194 -0
  76. package/dist/tools/tables.d.ts +35 -0
  77. package/dist/tools/tables.js +36 -0
  78. package/dist/tools/verify-row.d.ts +36 -0
  79. package/dist/tools/verify-row.js +38 -0
  80. package/dist/tools/workspaces.d.ts +140 -0
  81. package/dist/tools/workspaces.js +139 -0
  82. package/dist/utils/workspace-root.d.ts +1 -0
  83. package/dist/utils/workspace-root.js +39 -0
  84. package/package.json +46 -0
  85. package/skills/building-gtm-tables/SKILL.md +216 -0
  86. package/skills/building-gtm-tables/core/auto-execute.yaml +19 -0
  87. package/skills/building-gtm-tables/core/blueprint-schema.json +72 -0
  88. package/skills/building-gtm-tables/references/brief-to-blueprint.md +334 -0
  89. package/skills/building-gtm-tables/references/column-type-catalog.md +318 -0
  90. package/skills/building-gtm-tables/references/common-blueprints.fixtures.ts +199 -0
  91. package/skills/building-gtm-tables/references/common-blueprints.md +44 -0
  92. package/skills/building-gtm-tables/references/failure-taxonomy.md +197 -0
  93. package/skills/building-gtm-tables/references/uat-seed-prompts.md +37 -0
  94. package/skills/building-gtm-tables/references/verify-loop.md +74 -0
  95. package/skills/campaign-messages/SKILL.md +173 -0
  96. package/skills/campaign-messages/flow.v1.json +75 -0
  97. package/skills/craft-message/SKILL.md +401 -0
  98. package/skills/create-campaign/ARCHITECTURE.md +232 -0
  99. package/skills/create-campaign/DISCUSS.md +296 -0
  100. package/skills/create-campaign/FLOW_ASCII.md +240 -0
  101. package/skills/create-campaign/HOST-PARITY-CHECKLIST.md +49 -0
  102. package/skills/create-campaign/README.md +142 -0
  103. package/skills/create-campaign/SKILL.md +286 -0
  104. package/skills/create-campaign/context/README.md +67 -0
  105. package/skills/create-campaign/context/_TEMPLATE.md +12 -0
  106. package/skills/create-campaign/context/context.md +35 -0
  107. package/skills/create-campaign/context/learnings.md +16 -0
  108. package/skills/create-campaign/context/registry.json +19 -0
  109. package/skills/create-campaign/core/flow.v1.json +217 -0
  110. package/skills/create-campaign/core/policy.md +191 -0
  111. package/skills/create-campaign/core/providers/apollo.json +35 -0
  112. package/skills/create-campaign/core/providers/prospeo.json +34 -0
  113. package/skills/create-campaign/core/providers/registry.json +31 -0
  114. package/skills/create-campaign/core/providers/sales-nav.json +37 -0
  115. package/skills/create-campaign/core/providers/signal-discovery.json +42 -0
  116. package/skills/create-campaign/references/brief-template.md +64 -0
  117. package/skills/create-campaign/references/campaign-quality.md +84 -0
  118. package/skills/create-campaign/references/copy-calibration-examples.md +120 -0
  119. package/skills/create-campaign/references/offer-patterns.md +108 -0
  120. package/skills/create-campaign/references/provider-selection-strategy.md +212 -0
  121. package/skills/create-campaign/references/question-examples.md +167 -0
  122. package/skills/create-campaign/references/token-fill-examples.md +81 -0
  123. package/skills/create-campaign-brief/ARCHITECTURE.md +72 -0
  124. package/skills/create-campaign-brief/DISCUSS.md +64 -0
  125. package/skills/create-campaign-brief/README.md +176 -0
  126. package/skills/create-campaign-brief/SKILL.md +537 -0
  127. package/skills/create-campaign-brief/references/brief-synthesis-rules.md +100 -0
  128. package/skills/create-campaign-brief/references/brief-template.md +220 -0
  129. package/skills/create-campaign-brief/references/campaign-idea-options.md +30 -0
  130. package/skills/create-campaign-brief/references/copy-appendix-template.md +62 -0
  131. package/skills/create-campaign-brief/references/draft-lifecycle.md +23 -0
  132. package/skills/create-campaign-brief/references/examples/MANIFEST.json +89 -0
  133. package/skills/create-campaign-brief/references/examples/briefs/clover.md +223 -0
  134. package/skills/create-campaign-brief/references/examples/briefs/galley.md +222 -0
  135. package/skills/create-campaign-brief/references/examples/briefs/gelee.md +220 -0
  136. package/skills/create-campaign-brief/references/examples/briefs/hey-digital.md +234 -0
  137. package/skills/create-campaign-brief/references/examples/briefs/persona.md +231 -0
  138. package/skills/create-campaign-brief/references/examples/briefs/revvix.md +220 -0
  139. package/skills/create-campaign-brief/references/examples/briefs/sellable-dev.md +220 -0
  140. package/skills/create-campaign-brief/references/examples/briefs/superposition.md +233 -0
  141. package/skills/create-campaign-brief/references/examples/briefs/superpower.md +219 -0
  142. package/skills/create-campaign-brief/references/examples/briefs/westpark-villas.md +220 -0
  143. package/skills/create-campaign-brief/references/icp-lock-question-bank.md +43 -0
  144. package/skills/create-campaign-brief/references/messaging-inputs.md +58 -0
  145. package/skills/create-campaign-brief/references/output-acceptance-rubric.md +62 -0
  146. package/skills/create-campaign-brief/references/phase75-active-runtime-message-pack.md +248 -0
  147. package/skills/create-campaign-brief/references/phase75-canonical-brief-template.md +319 -0
  148. package/skills/create-campaign-brief/references/phase75-good-brief-and-messaging-examples.md +445 -0
  149. package/skills/create-campaign-brief/references/quick-research-protocol.md +39 -0
  150. package/skills/create-campaign-brief/references/reference-sheet-protocol.md +60 -0
  151. package/skills/create-campaign-brief/references/zero-shot-iteration-rules.md +66 -0
  152. package/skills/create-campaign-v2/SKILL.md +1619 -0
  153. package/skills/create-campaign-v2/core/auto-execute.README.md +219 -0
  154. package/skills/create-campaign-v2/core/auto-execute.yaml +121 -0
  155. package/skills/create-campaign-v2/core/flow.v2.json +1643 -0
  156. package/skills/create-campaign-v2/core/policy.md +82 -0
  157. package/skills/create-campaign-v2/references/ai-tells.md +253 -0
  158. package/skills/create-campaign-v2/references/approval-gate-framing.md +346 -0
  159. package/skills/create-campaign-v2/references/draft-lifecycle.md +110 -0
  160. package/skills/create-campaign-v2/references/escalation-ladder.md +119 -0
  161. package/skills/create-campaign-v2/references/filter-leads.md +495 -0
  162. package/skills/create-campaign-v2/references/final-handoff-contract.md +176 -0
  163. package/skills/create-campaign-v2/references/gold-standard-message-examples.md +394 -0
  164. package/skills/create-campaign-v2/references/gold-standard-message-patterns.md +314 -0
  165. package/skills/create-campaign-v2/references/gold-standard-message-validation-example.md +212 -0
  166. package/skills/create-campaign-v2/references/lead-validation-preview.md +172 -0
  167. package/skills/create-campaign-v2/references/parallel-critique-protocol.md +368 -0
  168. package/skills/create-campaign-v2/references/sample-validation-loop.md +289 -0
  169. package/skills/create-campaign-v2/references/step-13-import-leads.md +151 -0
  170. package/skills/create-campaign-v2/references/step-15-re-cascade.md +90 -0
  171. package/skills/create-campaign-v2/references/thomas-revision-filters.md +521 -0
  172. package/skills/create-campaign-v2/references/thomas-variant-selection.md +202 -0
  173. package/skills/create-campaign-v2/references/tier-routing-matrix.md +66 -0
  174. package/skills/create-campaign-v2/references/validation-criteria.md +367 -0
  175. package/skills/create-campaign-v2/references/watch-link-handoff.md +106 -0
  176. package/skills/create-campaign-v2-validation/SKILL.md +296 -0
  177. package/skills/create-post/SKILL.md +1308 -0
  178. package/skills/create-rubric/SKILL.md +251 -0
  179. package/skills/engage/SKILL.md +549 -0
  180. package/skills/engage/core/README.md +23 -0
  181. package/skills/engage/core/proven-searches.json +11 -0
  182. package/skills/engage/core/style-guide.template.md +47 -0
  183. package/skills/engage/core/tracked-people.json +10 -0
  184. package/skills/enrich-prospects/SKILL.md +97 -0
  185. package/skills/find-leads/SKILL.md +467 -0
  186. package/skills/generate-messages/SKILL.md +2361 -0
  187. package/skills/interview/SKILL.md +132 -0
  188. package/skills/interview/core/ENGAGE_STYLE_GUIDE.template.md +54 -0
  189. package/skills/interview/core/ICP.template.md +54 -0
  190. package/skills/interview/core/VOICE_PROFILE.template.md +101 -0
  191. package/skills/providers/apollo.md +520 -0
  192. package/skills/providers/prospeo.md +398 -0
  193. package/skills/providers/sales-nav.md +372 -0
  194. package/skills/providers/signal-discovery.md +495 -0
  195. package/skills/research/SKILL.md +258 -0
  196. package/skills/research/config.json +9 -0
  197. package/skills/research/override.md +13 -0
  198. package/skills/research-prospect/SKILL.md +99 -0
  199. package/skills/research-sender/SKILL.md +158 -0
  200. package/skills/workflow-sequences/SKILL.md +85 -0
@@ -0,0 +1,82 @@
1
+ # Create Campaign v2 Policy
2
+
3
+ This policy is the invariant layer for the from-scratch v2 orchestrator. Follow
4
+ it even if prompt prose is ambiguous.
5
+
6
+ ## 1) JSON State Machine First
7
+
8
+ `core/flow.v2.json` is the source of truth for:
9
+
10
+ - stage order
11
+ - required artifacts
12
+ - produced artifacts
13
+ - allowed tools
14
+ - forbidden tools
15
+ - wait events
16
+ - transitions
17
+
18
+ `SKILL.md` explains how to execute the flow. It does not replace the flow.
19
+
20
+ ## 2) Net-New Entry Point
21
+
22
+ Net-new v2 campaign creation starts at:
23
+
24
+ ```text
25
+ bootstrap -> brief-interview
26
+ ```
27
+
28
+ Do not start at `validate-artifacts` unless resuming a compatibility run where
29
+ the complete upstream artifact set already exists.
30
+
31
+ ## 3) No Mutation Before Approval
32
+
33
+ Before the user explicitly chooses `approve` at the commit gate, do not call:
34
+
35
+ - `create_campaign`
36
+ - `save_rubrics`
37
+ - `import_leads`
38
+ - `confirm_lead_list`
39
+ - `update_campaign`
40
+ - `queue_cells`
41
+ - `start_campaign`
42
+
43
+ Customer roleplay critique is advisory only. It cannot approve a campaign.
44
+
45
+ ## 4) Artifact Gates
46
+
47
+ Do not run a downstream stage until the active step's `requiredArtifacts` exist.
48
+ Intermediate user-review gates are interrupt-only: auto-continue when an
49
+ artifact is confirmed and no strategic tradeoff is present. The final commit
50
+ gate is the only mandatory pre-mint approval gate.
51
+
52
+ The minimum pre-approval chain is:
53
+
54
+ ```text
55
+ brief-v1.md / brief.md
56
+ lead-review.md
57
+ lead-sample.json
58
+ lead-filter.md
59
+ message-prep.md (optional)
60
+ message-candidate-drafts.md (optional, generated from find-leads basis rows)
61
+ message-validation.md
62
+ approval-packet.md
63
+ commit-gate-decision.md
64
+ ```
65
+
66
+ ## 5) Revision Routing
67
+
68
+ Revision choices route back to the exact upstream stage:
69
+
70
+ - `revise-brief` -> `brief-interview`
71
+ - `revise-leads` -> `find-leads`
72
+ - `revise-rubric` -> `filter-rubric`
73
+ - `revise-messaging` -> `message-generation`
74
+ - `abort` -> stop with zero DB mutation
75
+
76
+ ## 6) Post-Approval Tail
77
+
78
+ After `approve`, mint atomically with `create_campaign` and `save_rubrics`.
79
+ Only then surface the watch link and continue the cascade-driven tail.
80
+
81
+ The tail stops at `awaiting-user-greenlight`. Never call `start_campaign`
82
+ inside the autonomous tail.
@@ -0,0 +1,253 @@
1
+ # AI Tells — Canonical List
2
+
3
+ These are the patterns that make a cold message read as AI-generated,
4
+ not human-written. The message-validation Substance Filter 8 enforces
5
+ against this list. Add new tells here as we surface them in UAT — do
6
+ NOT bloat the filter itself.
7
+
8
+ Each tell has:
9
+
10
+ - **Pattern** — what to detect (regex-friendly description)
11
+ - **Why it's an AI tell** — the human-reasoning explanation
12
+ - **Allowed alternative** — what a hand-written message would do
13
+ instead
14
+ - **Severity** — `REJECT` (block message) or `WARN` (surface in
15
+ audit, do not auto-block)
16
+
17
+ ## Tell #1 — Body-level self-introduction
18
+
19
+ **Pattern:** `{{sender_first_name}} here.` / `Hey {{first_name}} —
20
+ {{sender_name}} here.` / `I'm {{sender_name}}` / `I'm the founder of
21
+ {{company}}` / sender-identification opening sentences.
22
+
23
+ **Why it's an AI tell:** Recipient sees who sent the message from
24
+ the LinkedIn UI (sender name + photo + headline at the top of the
25
+ thread). Body-level self-intro signals "I'm an automation that
26
+ doesn't know what UI you're reading me in." Real humans don't
27
+ introduce themselves in cold InMail — they open with substance.
28
+
29
+ **Allowed alternative:** Open directly with substance — `"Hey Bonnie
30
+ — pre-Patientdesk we ran our own dental call center for two
31
+ years..."` Or `"Hey Bonnie — building a thing for group dentistry I
32
+ think you'd have an opinion on..."`
33
+
34
+ **Severity:** REJECT
35
+
36
+ ## Tell #2 — Explicit recipient-fact reference in opener
37
+
38
+ **Pattern:** `Hey {{first_name}} — saw you posted...` / `Hey
39
+ {{first_name}}, your X is...` / `I noticed your...` / `Saw the X you
40
+ posted...` — opening sentence leads with a recipient-specific
41
+ reference.
42
+
43
+ **Why it's an AI tell:** Talking AT the recipient instead of WITH
44
+ them. Real founders open with their own reality, not by
45
+ interrogating the recipient's data feed. `"I noticed your..."` reads
46
+ as scraped intel.
47
+
48
+ **Allowed alternative:** Open with sender reality (Block 1); let
49
+ recipient gravity show up in Block 3 as a LIGHT callback. Refer to
50
+ their work CASUALLY without `"saw your X"`.
51
+
52
+ **Severity:** REJECT
53
+
54
+ ## Tell #3 — Explicit date or duration references about the recipient
55
+
56
+ **Pattern:** `"last month"`, `"yesterday"`, `"X months ago"`, `"six
57
+ months into"`, `"since YYYY"`, verbatim post-dates (`"2026-03-16"`),
58
+ tenure-clocking (`"six months into your CTO seat"`).
59
+
60
+ **Why it's an AI tell:** Humans don't track when someone posted to
61
+ within 30 days. Date precision = data scraping. Tenure clocking is
62
+ creepy.
63
+
64
+ **Allowed alternative:** `"Saw you've been thinking about X
65
+ recently"` (no date); `"you've been at this a while"` (no number);
66
+ skip the timestamp entirely.
67
+
68
+ **Severity:** REJECT
69
+
70
+ ## Tell #4 — Block-quoted verbatim recipient phrases
71
+
72
+ **Pattern:** Direct quotation marks around recipient's own words
73
+ longer than 4 words. E.g. `"Built SRE practice from scratch
74
+ supporting $0→$40M ARR growth"` inside the message body.
75
+
76
+ **Why it's an AI tell:** Real humans paraphrase or allude to what
77
+ someone said — they don't quote it back like a citation. Block
78
+ quotes scream "I scraped your profile and pasted the relevant
79
+ phrase."
80
+
81
+ **Allowed alternative:** Paraphrase the gist — `"you've spent years
82
+ building SRE from zero at scaling SaaS"`; reference the IDEA, not
83
+ the wording.
84
+
85
+ **Severity:** REJECT
86
+
87
+ ## Tell #5 — Explicit-source-citation phrases
88
+
89
+ **Pattern:** `"your bio says..."`, `"your profile shows..."`, `"the
90
+ post you wrote"`, `"the req you posted"`, `"saw on your LinkedIn"`,
91
+ `"your X-page mentions"`.
92
+
93
+ **Why it's an AI tell:** Hand-writing a message means you mention
94
+ the company or project naturally — you don't cite `"your bio"` as a
95
+ source. Citation-shape phrasing is a template leak.
96
+
97
+ **Allowed alternative:** Refer to their work or company directly
98
+ without naming the source.
99
+
100
+ **Severity:** REJECT
101
+
102
+ ## Tell #6 — Stack/feature lists in parentheses
103
+
104
+ **Pattern:** `(Datadog / PagerDuty / GitHub / AWS)` —
105
+ parenthetical-wrapped feature/stack dump.
106
+
107
+ **Why it's an AI tell:** Reads as marketing copy. Real founders
108
+ mention 1-2 named tools casually, in flow, not as a parenthetical
109
+ list.
110
+
111
+ **Allowed alternative:** `"hooks itself into your stack"`
112
+ (mechanism, no list); or weave 1-2 names naturally — `"plugs into
113
+ Datadog and PagerDuty without setup"`.
114
+
115
+ **Severity:** WARN (slashes inline in flow are tolerable;
116
+ parenthetical-wrapped lists are not)
117
+
118
+ ## Tell #7 — Over-precise formal numerics
119
+
120
+ **Pattern:** `"2 Q1 2026 pilot partners"`, `"spent the last eight
121
+ years"`, `"over 60+ clinics"`, `"Founded in 2024"`, `"27% of our
122
+ sample"`, `"three failure modes"`.
123
+
124
+ **Why it's an AI tell:** Spec-sheet specificity in a casual message.
125
+ Real humans say `"a couple this quarter"`, `"you've been at this a
126
+ while"`, `"dozens of clinics"`.
127
+
128
+ **Allowed alternative:** Casual quantifiers — `"a couple"`, `"a
129
+ few"`, `"dozens"`, `"a while"`.
130
+
131
+ **Severity:** WARN (REJECT if multiple in one message)
132
+
133
+ ## Tell #8 — Hardcoded signoff line
134
+
135
+ **Pattern:** Trailing `— {{sender_name}}` line, `Best, {{sender
136
+ _name}}`, `Cheers, {{sender_name}}`, `{{sender_name}}, co-founder at
137
+ {{company}}` as the last line.
138
+
139
+ **Why it's an AI tell:** Multi-sender pipelines hardcode breaks.
140
+ Recipient sees who sent it from LinkedIn UI. Body signoff is
141
+ redundant + brittle.
142
+
143
+ **Allowed alternative:** No signoff. Message ends with the CTA.
144
+
145
+ **Severity:** REJECT
146
+
147
+ ## Tell #9 — Founder-credibility flex without mechanism bridge
148
+
149
+ **Pattern:** Founder-origin sentence (`"I spent two years at X"`)
150
+ that does NOT immediately connect to the product mechanism. Pure
151
+ pedigree-flex.
152
+
153
+ **Why it's an AI tell:** A real founder mentions their background
154
+ only when it directly explains WHY the product works. Pure flex =
155
+ template.
156
+
157
+ **Allowed alternative:** Founder-origin sentence MUST be immediately
158
+ followed by a mechanism explanation — `"Long was on Roblox App/DB
159
+ Infra → that's why IncidentFox auto-builds integrations from your
160
+ codebase"`.
161
+
162
+ **Severity:** REJECT
163
+
164
+ ## Tell #10 — Vague-proof brags without named example
165
+
166
+ **Pattern:** `"multi-billion-dollar enterprises"`, `"Fortune 500"`,
167
+ `"leading SaaS"`, `"top scale-ups"`, `"trusted by leaders"` —
168
+ without naming a specific customer.
169
+
170
+ **Why it's an AI tell:** Vapor proof = worse than no proof. Buyers
171
+ immediately think "name one."
172
+
173
+ **Allowed alternative:** Either name a logo (with permission) or
174
+ strip to mechanism-only.
175
+
176
+ **Severity:** REJECT
177
+
178
+ ## Tell #11 — Formal CTA phrasing
179
+
180
+ **Pattern:** `"Worth a 20-min walkthrough?"`, `"Open to a brief
181
+ call?"`, `"Could I book some time on your calendar?"`.
182
+
183
+ **Why it's an AI tell:** Corporate cadence. Real founders write
184
+ casually — `"Worth 20?"`, `"Quick call this week or next?"`, `"20
185
+ min sometime?"`.
186
+
187
+ **Allowed alternative:** Casual founder cadence; under 8 words
188
+ preferred.
189
+
190
+ **Severity:** WARN
191
+
192
+ ## Tell #12 — Reusable opener that fits any recipient
193
+
194
+ **Pattern:** Opening sentence has zero row-specific detail and could
195
+ be sent unchanged to any of 50 recipients in the sample.
196
+
197
+ **Why it's an AI tell:** Broadcast spam. Real cold InMail earns its
198
+ right to the inbox with at least one row-specific reference.
199
+
200
+ **Allowed alternative:** At least one line in the body must
201
+ reference something verifiable about THIS recipient (project, role,
202
+ company, recent work).
203
+
204
+ **Severity:** REJECT
205
+
206
+ ## Tell #13 — Em dash in message body
207
+
208
+ **Pattern:** Any U+2014 em dash character (`—`) anywhere in the
209
+ message body text. Includes em dashes used as parenthetical pauses
210
+ (`"works best for the exact hire you're in the middle of — founding
211
+ engineer, has to ship..."`), em dashes joining two independent
212
+ clauses, and em dashes wrapping an appositive phrase.
213
+
214
+ **Why it's an AI tell:** Em dashes are the single most reliable
215
+ signature of LLM-generated prose in casual-founder text. Real
216
+ founders typing a cold InMail on a phone or desktop almost never
217
+ reach for an em dash — they use commas, periods, parentheses, or
218
+ a hyphen-minus (`-`) when they want a pause. LLMs default to em
219
+ dashes for rhythm because they were trained on edited published
220
+ prose where em dashes are frequent. A message with even ONE em dash
221
+ reads as AI-polished, not hand-typed. Surfaced during Phase 94
222
+ Skillsync run (Plan 07): generator self-declared "NO em dashes" as
223
+ an invariant but still emitted one in the Selected Winner's Block
224
+ 2 because the catalog did not yet codify the pattern.
225
+
226
+ **Allowed alternative:** Use commas, periods (break into two
227
+ sentences), parentheses, or a hyphen-minus (`-`) for pauses. If the
228
+ thought needs dashes to feel right, rewrite as two short sentences.
229
+ Example — instead of `"works best for the exact hire you're in the
230
+ middle of — founding engineer, has to ship production day one"`,
231
+ write `"works best for the exact hire you're making. founding
232
+ engineer, ships production day one."`.
233
+
234
+ **Severity:** REJECT
235
+
236
+ **Note:** This tell applies ONLY to the message body. Em dashes in
237
+ reference-file text, brief-template text, prompt text, and audit
238
+ notes are fine — this is a body-level output guard, not a
239
+ general-prose style rule.
240
+
241
+ ---
242
+
243
+ ## How to add new tells
244
+
245
+ 1. Surface the tell during UAT — it must be a pattern we saw in an
246
+ actual generated message that read as AI-written.
247
+ 2. Name it `Tell #N` with a short descriptive title.
248
+ 3. Fill in Pattern / Why / Allowed alternative / Severity.
249
+ 4. The Filter 8 check automatically picks it up — do not touch
250
+ `thomas-revision-filters.md` Filter 8 spec when adding tells.
251
+ 5. Add a corresponding test case in
252
+ `tests/scripts/skill-references-substance-filters.test.ts` if
253
+ the new tell needs regression coverage.
@@ -0,0 +1,346 @@
1
+ # Approval Gate Framing
2
+
3
+ This reference governs the commit gate in create-campaign-v2. Load this file
4
+ before showing the user the approval packet at the end of Phase 84 and before
5
+ minting a real `CampaignOffer`.
6
+
7
+ ## Purpose
8
+
9
+ The approval gate is the **only** place in create-campaign-v2 where the user
10
+ authorizes a DB mutation. Everything upstream (Phase 83 brief + Phase 84
11
+ validation artifacts) is file-only. Everything downstream (atomic mint +
12
+ autonomous tail) is live campaign state.
13
+
14
+ No campaign row exists until the user picks `approve`.
15
+
16
+ ## Preconditions
17
+
18
+ Before showing the commit gate, the draft directory must contain all of:
19
+
20
+ - `brief.md`
21
+ - `lead-review.md`
22
+ - `lead-sample.json`
23
+ - `lead-filter.md`
24
+ - `message-validation.md`
25
+ - `approval-packet.md`
26
+
27
+ The current run must also have retrieved the real message-generation prompt
28
+ through `get_message_prompt({ promptName: "generate-messages" })` or
29
+ `get_subskill_prompt({ subskillName: "generate-messages" })` before
30
+ `message-validation.md`, `approval-packet.md`, or the commit gate is written.
31
+ If the message template was written directly from memory or planning artifacts,
32
+ do not show the commit gate; route back to message generation.
33
+
34
+ `rubric.json` is optional but strongly preferred — when missing, derive it from
35
+ `lead-filter.md` in the atomic mint step.
36
+
37
+ `lead-source-intake.json` is optional for normal discovery and required when
38
+ the user intentionally supplied a source. If present, the approval packet must
39
+ summarize the source type, input mode, supplied profile/domain/list count,
40
+ sampled count, what will be materialized after approval, and that only the
41
+ review batch will be enriched/messaged before greenlight.
42
+ Use the phrase "only the review batch" plainly enough that the operator
43
+ understands approval is not permission to process the full supplied source.
44
+
45
+ If any required artifact is missing, do NOT show the gate. Route back to the
46
+ first missing step instead.
47
+
48
+ ### Workspace + sender invariant (Step 0, before any commit-gate action)
49
+
50
+ Before showing the gate OR running any approve-path tool, verify the
51
+ **workspace/sender invariant**:
52
+
53
+ - The sender configured in the committed `CampaignOffer` draft resolves
54
+ inside the currently-authenticated workspace.
55
+ - The active Sellable-auth workspace matches the workspace the draft
56
+ directory was written in (prevents cross-workspace mint drift).
57
+
58
+ This invariant is identical to the Phase 84 "sender/workspace mismatch
59
+ = abort" rule and the global memory rule `CRITICAL: Never Send Messages
60
+ From Wrong Workspace`. If the invariant fails:
61
+
62
+ 1. Do NOT show the commit gate.
63
+ 2. Do NOT call `bootstrap_create_campaign`, `create_campaign`, or
64
+ `save_rubrics`.
65
+ 3. Surface an explicit workspace/sender-mismatch error + the detected
66
+ current-workspace vs expected-workspace diagnostic.
67
+ 4. Leave the draft directory intact; a fresh session in the correct
68
+ workspace can resume from where this one aborted.
69
+
70
+ The invariant is a hard stop, not an escalation in the Plan 85-02 sense.
71
+
72
+ ## Anchor Validation
73
+
74
+ Before showing the gate, walk the required artifacts and confirm anchors are
75
+ populated:
76
+
77
+ - `brief.md` has a non-empty `## Message Thesis` section
78
+ - `lead-review.md` has a `Status` of `confirmed` (not `rejected` or `unclear`)
79
+ - `lead-sample.json` parses and contains at least one lead row
80
+ - `lead-filter.md` has `Decision`, `Who We'll Keep`, `Who We'll Exclude`,
81
+ `Required Keep Rules`, `Required Exclude Rules`, `Pass Rate`,
82
+ `Recommendation`, and `Implementation Details` sections
83
+ - `message-validation.md` has `Status: confirmed`, `Mode: DRY MODE (no DB mutation)`,
84
+ a `Selected Winner`, and a non-empty `Token Adherence Table`
85
+
86
+ An empty anchor blocks `approve`. The user can still pick a revision choice.
87
+
88
+ ## Approval Packet
89
+
90
+ Build the approval packet in user-facing order and write it to
91
+ `approval-packet.md` before the gate is shown. The file is the exact packet the
92
+ user is approving, not a private scratch note.
93
+
94
+ When rendering the approval packet inline for the customer, start it with
95
+ exactly:
96
+
97
+ ```text
98
+ Status: approval-packet
99
+ ```
100
+
101
+ The same assistant turn must then call `AskUserQuestion` with the six commit
102
+ choices. Do not show a standalone commit-gate question in a later turn without
103
+ the approval packet above it.
104
+
105
+ The packet should read like an AI GTM engineer explaining the campaign, not an
106
+ internal validation report. Start with the practical direction in plain
107
+ language: who we will contact, why this buyer should care, what lead source we
108
+ will use, what the first message says, and what happens if the user approves.
109
+ Keep implementation details available, but move them below the customer-facing
110
+ summary.
111
+
112
+ 1. **brief** — `brief.md` thesis, product, ICP, offer
113
+ 2. **lead sample** — first 5-10 rows from `lead-sample.json` rendered as
114
+ `Name / Title / Company` lines, plus the `lead-review.md` pass-rate
115
+ and supplied-source framing when `lead-source-intake.json` exists:
116
+ supplied people list, existing Sellable lead list, or supplied account list
117
+ plus people search
118
+ 3. **lead filter** — the `Decision`, `Who We'll Keep`, `Who We'll Exclude`,
119
+ `Pass Rate`, and `Recommendation` blocks from `lead-filter.md`; keep
120
+ rubric internals in `Implementation Details` unless the user asks to inspect
121
+ the saved filter criteria
122
+ 4. **message validation** — the `Selected Winner` from `message-validation.md`,
123
+ rendered as it will appear in the outbound, plus the `Findings` + `Recommendation`
124
+
125
+ The packet must include a dedicated `## Message Review` section immediately
126
+ before `## Approved Message Template`. This is the customer-facing messaging
127
+ gate. It should not be a raw validation dump; it should answer:
128
+
129
+ - `Verdict:` strong / usable-but-could-improve / needs-revision
130
+ - `What works:` why the message is likely to earn replies
131
+ - `What I would improve before launch:` the biggest remaining concern, or
132
+ `none` if it is ready
133
+ - `Recommendation:` approve-message / revise-messaging
134
+
135
+ If the validation says `revise-message`, do not bury that in caveats. Show the
136
+ draft if useful, mark `Recommendation: revise-messaging`, and route the user to
137
+ the `revise-messaging` commit-gate option instead of implying the campaign is
138
+ ready.
139
+
140
+ If `message-validation.md` has an extractable `Selected Winner`, the packet's
141
+ `## Approved Message Template` must use that winner exactly, except for
142
+ supported prospect-row `{{tokens}}`. Do not write a fresh approval-template
143
+ message from the brief. If no winner/template can be extracted, this exact-match
144
+ gate is skipped, but the packet still needs a usable approved template unless
145
+ the user explicitly chose AI-generated messages.
146
+
147
+ Do NOT render the packet as a bundle of opaque validation anchors or a dump
148
+ of raw JSON. The user is approving a live campaign — they need to see what
149
+ they are approving.
150
+
151
+ Do NOT use opaque words like `anchor`, `chosen lane`, `validation artifact`,
152
+ or `provider path` in the top customer-facing section. Use plain labels:
153
+ target prospects, lead source, expected usable leads, filters, message, risks,
154
+ and next step.
155
+
156
+ If a customer/operator roleplay pass is run before the gate, write its critique
157
+ to `customer-roleplay.md`. That critique is advisory only. A positive roleplay
158
+ result is not approval and must not trigger `create_campaign`,
159
+ `save_rubrics`, or any other DB mutation.
160
+
161
+ After the user/operator chooses, write `commit-gate-decision.md` with exactly
162
+ one of the six allowed choices plus a short reason. This file is the durable
163
+ authorization record for the branch taken. Only `Decision: approve` authorizes
164
+ atomic mint.
165
+
166
+ ### Packet framing rule (never say "anchor")
167
+
168
+ The user-visible packet MUST use the product-facing section names:
169
+
170
+ - **brief**
171
+ - **lead sample**
172
+ - **lead filter**
173
+ - **messages** (or **message validation** when emphasizing the validation mode)
174
+
175
+ The internal skill vocabulary uses "anchor validation" to describe the
176
+ presence/non-emptiness checks in §Anchor Validation above — that's fine for
177
+ internal skill state. But the USER-FACING packet MUST NOT use "anchor,"
178
+ "validation anchor," "draft anchor," or any other anchor-prefixed term.
179
+ "Anchor" is an implementation word; it reads as opaque to operators.
180
+
181
+ Example — correct vs incorrect packet headers:
182
+
183
+ | Correct (product-facing) | Incorrect (opaque anchor framing) |
184
+ | ------------------------------------------- | ---------------------------------------------------- |
185
+ | "Here's the **brief** you're about to ship" | "Here's the **brief anchor** in the draft directory" |
186
+ | "The **lead sample** shows 10 top rows" | "The **lead-sample anchor** validates" |
187
+ | "**Messages** — winner from 3 candidates" | "**Message-validation anchor** Status: confirmed" |
188
+
189
+ ## Commit Gate Choices
190
+
191
+ The gate offers exactly these 6 choices, in this order:
192
+
193
+ ```text
194
+ approve
195
+ revise-brief
196
+ revise-leads
197
+ revise-rubric
198
+ revise-messaging
199
+ abort
200
+ ```
201
+
202
+ Use `AskUserQuestion` with these 6 options. Do not collapse, reorder, or add
203
+ choices. Do not auto-select.
204
+
205
+ If the host UI limits options per question, preserve all six routes with a
206
+ two-question gate instead of mentioning implementation limits:
207
+
208
+ 1. Decision: `approve`, `revise`, `abort`
209
+ 2. Revise route: `revise-brief`, `revise-leads`, `revise-rubric`,
210
+ `revise-messaging`
211
+
212
+ In this split form, `revise` is not a seventh route; it is only the parent
213
+ choice that activates the second question.
214
+
215
+ ## Choice Semantics
216
+
217
+ ### `approve`
218
+
219
+ User authorizes atomic mint. Proceed to the atomic-mint step:
220
+
221
+ 0. **verify workspace/sender invariant** (see §Preconditions) — if the
222
+ invariant fails, abort BEFORE `bootstrap_create_campaign`
223
+ 1. `bootstrap_create_campaign({ flowVersion: "v2" })`
224
+ 2. `create_campaign({ campaignBrief, currentStep: "auto-execute-leads" })`
225
+ → capture `{ campaignId, watchUrl }` from response
226
+ 3. `save_rubrics({ campaignOfferId, rubric })` using `rubric.json` (or derived
227
+ payload from `lead-filter.md`)
228
+ 4. flip brief status to `committed`; move draft to `.committed/`
229
+ 5. surface the watch link using `watch-link-handoff.md`
230
+ 6. hand off to the autonomous tail (Plan 85-02)
231
+
232
+ See `watch-link-handoff.md` for the exact link-surfacing protocol and the
233
+ partial-mint recovery rules.
234
+
235
+ ### `save_rubrics` partial-mint recovery preference
236
+
237
+ When `create_campaign` succeeds but `save_rubrics` fails, the recovery
238
+ path preference is **recoverable-failure state + explicit retry**, NOT
239
+ rollback of the CampaignOffer row.
240
+
241
+ Rationale:
242
+
243
+ - `save_rubrics` is idempotent — the operator can retry the same call
244
+ without duplicating state.
245
+ - The operator may want to inspect the in-flight campaign row (via the
246
+ watch link) before deciding whether to retry or abort.
247
+ - Rollback would destroy a useful artifact (the minted campaign row +
248
+ persisted brief) that the operator may want to keep while
249
+ debugging the rubric save.
250
+
251
+ Implementation:
252
+
253
+ 1. Do NOT call the delete path on the CampaignOffer row.
254
+ 2. Mark the campaign in a `currentStep` state that the skill can
255
+ detect on resume (e.g. `auto-execute-leads-rubric-pending`).
256
+ 3. Surface the failure with the specific error + retry instructions.
257
+ 4. Do NOT surface the watch link until `save_rubrics` succeeds — per
258
+ `watch-link-handoff.md` §Partial-Mint Recovery, the link points
259
+ at a live, fully-minted campaign; a half-minted one is misleading.
260
+ 5. On retry, call `save_rubrics` again with the same payload. If it
261
+ succeeds, the tail resumes normally.
262
+
263
+ Rollback remains available as an operator-driven escape hatch via the
264
+ `abort` gate choice on resume — but the default recovery is NOT
265
+ automatic rollback.
266
+
267
+ ### `revise-brief`
268
+
269
+ Route back to Phase 83 or Phase 84 depending on what the user wants to change.
270
+ Do NOT mint a campaign. Do NOT print a watch link.
271
+
272
+ Draft effect: preserve nothing by default; the brief itself is usually
273
+ rewritten upstream. Delete all downstream artifacts so Phase 84 will re-run:
274
+
275
+ - delete `lead-review.md`
276
+ - delete `lead-sample.json`
277
+ - delete `lead-filter.md`
278
+ - delete `message-validation.md`
279
+ - delete `rubric.json` if present
280
+
281
+ ### `revise-leads`
282
+
283
+ Route back to Phase 84 `find leads`. Do NOT mint a campaign. Do NOT print a
284
+ watch link.
285
+
286
+ Draft effect:
287
+
288
+ - preserve `brief.md`
289
+ - delete `lead-review.md`
290
+ - delete `lead-sample.json`
291
+ - delete `lead-filter.md`
292
+ - delete `message-validation.md`
293
+ - delete `rubric.json` if present
294
+
295
+ ### `revise-rubric`
296
+
297
+ Route back to Phase 84 `filter leads`. Do NOT mint a campaign. Do NOT print a
298
+ watch link.
299
+
300
+ Draft effect:
301
+
302
+ - preserve `brief.md`
303
+ - preserve `lead-review.md`
304
+ - preserve `lead-sample.json`
305
+ - delete `lead-filter.md`
306
+ - delete `message-validation.md`
307
+ - delete `rubric.json` if present
308
+
309
+ ### `revise-messaging`
310
+
311
+ Route back to Phase 84 `generate message`. Do NOT mint a campaign. Do NOT
312
+ print a watch link.
313
+
314
+ Draft effect:
315
+
316
+ - preserve `brief.md`
317
+ - preserve `lead-review.md`
318
+ - preserve `lead-sample.json`
319
+ - preserve `lead-filter.md`
320
+ - delete `message-validation.md`
321
+ - preserve `rubric.json` if present
322
+
323
+ ### `abort`
324
+
325
+ User cancels the session. Do NOT mint a campaign. Do NOT print a watch link.
326
+
327
+ Draft effect: move the draft directory to
328
+ `.sellable/create-campaign-v2/drafts/{workspace-slug}/.aborted/{campaign-slug}-{timestamp}/`.
329
+ No DB rows touched. No `CampaignOffer` created.
330
+
331
+ ## Hard Rules
332
+
333
+ - The user's `approve` choice is the **only** trigger for live DB mutation.
334
+ - A positive `customer-roleplay.md` critique is not approval and produces zero
335
+ DB mutation unless `commit-gate-decision.md` explicitly says
336
+ `Decision: approve`.
337
+ - The commit gate must not call `create_campaign`, `save_rubrics`,
338
+ `import_leads`, `update_campaign`, or any other mutating tool before the
339
+ user picks a choice.
340
+ - `import_leads` is **not** part of atomic mint. Full sourcing/import happens
341
+ in Plan 85-02 Step 13 after mint.
342
+ - Revision choices produce ZERO DB rows.
343
+ - Aborting produces ZERO DB rows.
344
+ - A failed `approve` path (e.g. `create_campaign` errors, or `save_rubrics`
345
+ fails after campaign creation) does NOT surface a watch link. See
346
+ `watch-link-handoff.md` for the partial-mint recovery protocol.