@sellable/mcp 0.1.267 → 0.1.269
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/dist/index-dev.js +0 -0
- package/dist/index.js +0 -0
- package/dist/server.js +8 -7
- package/dist/tools/content-posts.d.ts +1 -421
- package/dist/tools/content-posts.js +0 -802
- package/dist/tools/engage-discovery.d.ts +0 -24
- package/dist/tools/engage-discovery.js +9 -114
- package/dist/tools/harvest-jobs.d.ts +182 -0
- package/dist/tools/harvest-jobs.js +429 -0
- package/dist/tools/leads.js +1 -1
- package/dist/tools/registry.d.ts +47 -76
- package/dist/tools/registry.js +2 -0
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +10 -0
- package/skills/create-campaign/core/providers/prospeo.json +5 -2
- package/skills/create-post/SKILL.md +32 -605
- package/skills/create-post/references/hook-research-playbook.md +31 -460
- package/skills/create-post/references/post-file-contract.md +0 -36
- package/skills/create-post/references/post-validation.md +27 -258
- package/skills/create-post/references/premise-development.md +7 -298
- package/skills/providers/prospeo.md +21 -0
- package/skills/create-post/references/linkedin-preview-rendering.md +0 -221
- package/skills/research/config.json +0 -9
|
@@ -1,42 +1,16 @@
|
|
|
1
|
-
# Premise Development
|
|
1
|
+
# Premise Development
|
|
2
2
|
|
|
3
3
|
A strong post is not an idea with a better hook. A strong post is a valuable
|
|
4
4
|
premise wrapped in a sharp opening.
|
|
5
5
|
|
|
6
|
-
Use this stage after
|
|
7
|
-
|
|
8
|
-
post positioning breakdowns, viral-post outlines, hook-to-body promise maps, and
|
|
9
|
-
body expression inputs.
|
|
10
|
-
|
|
11
|
-
Do not generate hook candidates until at least one `Premise Card` exists and at
|
|
12
|
-
least one source template has either been selected or explicitly rejected as a
|
|
13
|
-
poor fit.
|
|
6
|
+
Use this stage after market/hook research and before hook candidates. Do not
|
|
7
|
+
generate hook candidates until at least one `Premise Card` exists.
|
|
14
8
|
|
|
15
9
|
## Goal
|
|
16
10
|
|
|
17
11
|
Turn the raw idea into a real story, observed tension, or useful argument that a
|
|
18
12
|
specific reader would care about.
|
|
19
13
|
|
|
20
|
-
Use this post tension framework when evaluating whether the premise can hold
|
|
21
|
-
attention:
|
|
22
|
-
|
|
23
|
-
```text
|
|
24
|
-
Belief -> Contradiction -> Stakes -> Proof -> Mechanism -> Reframe -> Useful Move
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
- `Belief`: what the reader already thinks or wants to be true
|
|
28
|
-
- `Contradiction`: what the source story reveals that does not fit the belief
|
|
29
|
-
- `Stakes`: what the reader loses if they keep believing the old version
|
|
30
|
-
- `Proof`: the scene, number, repeated pattern, or concrete artifact that makes
|
|
31
|
-
the contradiction credible
|
|
32
|
-
- `Mechanism`: why the thing actually works or fails
|
|
33
|
-
- `Reframe`: the sharper way to see the problem after the mechanism is clear
|
|
34
|
-
- `Useful Move`: what the reader can do, notice, stop doing, or test next
|
|
35
|
-
|
|
36
|
-
A post feels "edge of seat" when the hook creates a contradiction the target
|
|
37
|
-
reader cares about, the body delays the answer only while adding proof, and each
|
|
38
|
-
beat either raises tension or repays tension. If a beat does neither, cut it.
|
|
39
|
-
|
|
40
14
|
The premise must answer:
|
|
41
15
|
|
|
42
16
|
- who this is for
|
|
@@ -48,8 +22,6 @@ The premise must answer:
|
|
|
48
22
|
- why now
|
|
49
23
|
- why this user can credibly say it
|
|
50
24
|
- what proof is available and what proof is missing
|
|
51
|
-
- which source template, if any, should shape the narrative
|
|
52
|
-
- which positioning sequence the user's post should follow
|
|
53
25
|
|
|
54
26
|
If the premise has no real scene, no tension, and no reader value, stop before
|
|
55
27
|
drafting. Ask for the missing story or save only a `needs_revision` premise
|
|
@@ -61,14 +33,10 @@ Before writing premise cards, search the available source material:
|
|
|
61
33
|
|
|
62
34
|
- raw idea text
|
|
63
35
|
- voice memo or transcript if provided
|
|
64
|
-
- `Transcript Worldview Packet` from create-post capture
|
|
65
36
|
- `core/story-bank.md`
|
|
66
37
|
- `core/answer-bank.md`
|
|
67
38
|
- `core/proof-ledger.md`
|
|
68
39
|
- `core/wins-ledger.md`
|
|
69
|
-
- `core/transcripts/INDEX.md`
|
|
70
|
-
- `core/content-memory/INDEX.md`, relevant clusters, cards, questions, and
|
|
71
|
-
post seeds
|
|
72
40
|
- approved references and gold standards
|
|
73
41
|
- current-session user corrections or rejections
|
|
74
42
|
|
|
@@ -80,37 +48,11 @@ Look for:
|
|
|
80
48
|
- a before/after: what changed in the user's belief
|
|
81
49
|
- a specific object: Slack note, customer call, campaign table, reply, list,
|
|
82
50
|
demo, failed draft, stale idea, messy workflow
|
|
83
|
-
- repeated worldview: the user's recurring operating belief behind the idea
|
|
84
|
-
- hot-take ingredient: the specific advice, default behavior, or market cliche
|
|
85
|
-
the user is pushing against
|
|
86
51
|
|
|
87
52
|
If no real story is present, use an observed pattern only if it is traceable to
|
|
88
53
|
the raw source or memory. Mark the gap in the premise card. Do not fabricate a
|
|
89
54
|
customer, call, outcome, date, metric, or private scene.
|
|
90
55
|
|
|
91
|
-
## Worldview And Hot-Take Extraction
|
|
92
|
-
|
|
93
|
-
Before scoring premise cards, extract the user's source-backed worldview from
|
|
94
|
-
the transcript packet:
|
|
95
|
-
|
|
96
|
-
```text
|
|
97
|
-
Worldview extraction:
|
|
98
|
-
- worldview claim:
|
|
99
|
-
- source transcript/cluster/card:
|
|
100
|
-
- repeated phrase or language pattern:
|
|
101
|
-
- lived proof behind it:
|
|
102
|
-
- common advice it challenges:
|
|
103
|
-
- hot take version:
|
|
104
|
-
- public-safe version:
|
|
105
|
-
- private/sensitive material to avoid:
|
|
106
|
-
- confidence: strong | medium | weak
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
A good hot take is not just a contrarian sentence. It must trace to something
|
|
110
|
-
the user has said, seen, shipped, sold, or learned repeatedly. If the hot take
|
|
111
|
-
only exists because an outside creator framed it well, mark it as borrowed and
|
|
112
|
-
do not use it as the user's premise.
|
|
113
|
-
|
|
114
56
|
## Premise Cards
|
|
115
57
|
|
|
116
58
|
Generate 3-5 premise cards before hooks. Each card must use this shape:
|
|
@@ -139,7 +81,7 @@ tension:
|
|
|
139
81
|
reader value:
|
|
140
82
|
<what the reader learns, sees differently, or can do after reading>
|
|
141
83
|
|
|
142
|
-
why now /
|
|
84
|
+
why now / market heat:
|
|
143
85
|
<what current research says is resonating>
|
|
144
86
|
|
|
145
87
|
credible why-us:
|
|
@@ -151,32 +93,14 @@ proof available:
|
|
|
151
93
|
proof missing:
|
|
152
94
|
<claims that cannot be made yet>
|
|
153
95
|
|
|
154
|
-
worldview source:
|
|
155
|
-
<transcript/cluster/card/source-backed belief used>
|
|
156
|
-
|
|
157
|
-
hot take:
|
|
158
|
-
<public-safe sharp version of the user's source-backed disagreement>
|
|
159
|
-
|
|
160
96
|
best frame:
|
|
161
97
|
story | contrarian take | teardown | founder confession | future thesis | lesson
|
|
162
98
|
|
|
163
|
-
source template fit:
|
|
164
|
-
<selected source template name or none>
|
|
165
|
-
|
|
166
|
-
positioning sequence to test:
|
|
167
|
-
<Category -> Category -> Category -> ...>
|
|
168
|
-
|
|
169
|
-
viral outline to adapt:
|
|
170
|
-
<beat names from selected source template, rewritten for this user's story>
|
|
171
|
-
|
|
172
99
|
hook territories:
|
|
173
100
|
- <territory 1>
|
|
174
101
|
- <territory 2>
|
|
175
102
|
- <territory 3>
|
|
176
103
|
|
|
177
|
-
body expression inputs:
|
|
178
|
-
- <line shape, proof slot, story beat, mechanism explanation, or closing move>
|
|
179
|
-
|
|
180
104
|
risk:
|
|
181
105
|
<why this premise might still be weak>
|
|
182
106
|
|
|
@@ -184,214 +108,6 @@ score:
|
|
|
184
108
|
<1-100 with short reason>
|
|
185
109
|
```
|
|
186
110
|
|
|
187
|
-
## Template-Aware Premise Selection
|
|
188
|
-
|
|
189
|
-
Do not treat source templates as decoration. A source template is useful only
|
|
190
|
-
when its narrative engine matches something the user can credibly say.
|
|
191
|
-
|
|
192
|
-
For each premise card, compare it against the selected keeper templates from
|
|
193
|
-
hook research:
|
|
194
|
-
|
|
195
|
-
```text
|
|
196
|
-
Template fit check:
|
|
197
|
-
premise:
|
|
198
|
-
source_template:
|
|
199
|
-
template narrative engine:
|
|
200
|
-
matching user story/proof:
|
|
201
|
-
missing user story/proof:
|
|
202
|
-
positioning sequence fit:
|
|
203
|
-
hook promise fit:
|
|
204
|
-
body payoff fit:
|
|
205
|
-
voice fit:
|
|
206
|
-
borrow:
|
|
207
|
-
do not borrow:
|
|
208
|
-
fit verdict: strong | partial | weak | reject
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
Reject a template when it depends on source-specific proof, celebrity reach,
|
|
212
|
-
personal context the user does not have, or a body structure that would force a
|
|
213
|
-
fake story. Prefer a less viral template that fits the user's real proof over a
|
|
214
|
-
more viral template that requires borrowed authority.
|
|
215
|
-
|
|
216
|
-
## Viral Narrative Structure
|
|
217
|
-
|
|
218
|
-
Once a premise and source template are selected, create the user's viral-post
|
|
219
|
-
outline before writing body prose.
|
|
220
|
-
|
|
221
|
-
Use this format:
|
|
222
|
-
|
|
223
|
-
```text
|
|
224
|
-
User viral-post outline:
|
|
225
|
-
selected_premise:
|
|
226
|
-
selected_source_template:
|
|
227
|
-
hook_promise:
|
|
228
|
-
see_more_tension:
|
|
229
|
-
body_payoff:
|
|
230
|
-
positioning_sequence:
|
|
231
|
-
<Category> -> <Category> -> <Category> -> ...
|
|
232
|
-
|
|
233
|
-
beats:
|
|
234
|
-
1.
|
|
235
|
-
beat_name:
|
|
236
|
-
narrative_job:
|
|
237
|
-
user_story_or_proof:
|
|
238
|
-
positioning_categories:
|
|
239
|
-
reader_state_before:
|
|
240
|
-
reader_state_after:
|
|
241
|
-
line_shape_to_test:
|
|
242
|
-
proof_safety:
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
The outline should preserve the source template's useful narrative jobs while
|
|
246
|
-
replacing all source-specific proof, scenes, status, jokes, and examples with
|
|
247
|
-
the user's material.
|
|
248
|
-
|
|
249
|
-
## Body Expression Lab
|
|
250
|
-
|
|
251
|
-
After the selected hook and viral-post outline exist, generate body expression
|
|
252
|
-
candidates before writing the final draft. This is where the system tests
|
|
253
|
-
different ways to express the same structure.
|
|
254
|
-
|
|
255
|
-
Generate 5-8 body expression candidates. Every candidate must use:
|
|
256
|
-
|
|
257
|
-
- the same selected hook or hook territory
|
|
258
|
-
- the same selected premise
|
|
259
|
-
- the same viral-post outline
|
|
260
|
-
- the same positioning sequence
|
|
261
|
-
- only user-sourced story and proof
|
|
262
|
-
|
|
263
|
-
Each candidate should vary the expression, not the facts:
|
|
264
|
-
|
|
265
|
-
```text
|
|
266
|
-
Body expression candidate:
|
|
267
|
-
name:
|
|
268
|
-
expression_strategy:
|
|
269
|
-
opening_after_hook:
|
|
270
|
-
beat_lines:
|
|
271
|
-
1. <line or paragraph>
|
|
272
|
-
2. <line or paragraph>
|
|
273
|
-
positioning_sequence_coverage:
|
|
274
|
-
hook_promise_repaid:
|
|
275
|
-
best_lines:
|
|
276
|
-
weak_lines:
|
|
277
|
-
proof_risk:
|
|
278
|
-
voice_risk:
|
|
279
|
-
score:
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
Useful expression strategies:
|
|
283
|
-
|
|
284
|
-
- plain field guide
|
|
285
|
-
- founder confession
|
|
286
|
-
- proof-first roadmap
|
|
287
|
-
- teardown then replacement
|
|
288
|
-
- scene then lesson
|
|
289
|
-
- enemy naming then mechanism
|
|
290
|
-
- compact build-in-public note
|
|
291
|
-
|
|
292
|
-
Do not create candidates by changing the claim. Create candidates by changing
|
|
293
|
-
line order, amount of scene, proof placement, rhythm, and how the mechanism is
|
|
294
|
-
explained.
|
|
295
|
-
|
|
296
|
-
## Combine Pass
|
|
297
|
-
|
|
298
|
-
After body expression candidates are scored, combine the best parts into one
|
|
299
|
-
draft outline before prose.
|
|
300
|
-
|
|
301
|
-
Record:
|
|
302
|
-
|
|
303
|
-
```text
|
|
304
|
-
Combined body plan:
|
|
305
|
-
selected_hook:
|
|
306
|
-
selected_expression_parts:
|
|
307
|
-
lines_kept:
|
|
308
|
-
lines_rewritten:
|
|
309
|
-
lines_cut:
|
|
310
|
-
positioning_sequence_final:
|
|
311
|
-
hook_promise_repayment:
|
|
312
|
-
proof_gaps_remaining:
|
|
313
|
-
why_this_combination_wins:
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
If no candidate repays the hook promise with real user proof, return to premise
|
|
317
|
-
development or ask the user for the missing story. Do not save a `ready` draft.
|
|
318
|
-
|
|
319
|
-
## Pre-Draft Narrative Outline
|
|
320
|
-
|
|
321
|
-
Before final prose, produce a compact `Pre-Draft Narrative Outline`. This is the
|
|
322
|
-
user-visible argument skeleton that lets the user confirm what the post is
|
|
323
|
-
trying to say, in what order, and which proven body shapes are being adapted
|
|
324
|
-
before the system writes body copy.
|
|
325
|
-
|
|
326
|
-
Use this format:
|
|
327
|
-
|
|
328
|
-
```text
|
|
329
|
-
Pre-Draft Narrative Outline
|
|
330
|
-
I. Hook and click debt
|
|
331
|
-
A. Selected hook: <selected hook>
|
|
332
|
-
B. Rendered mobile preview verdict: <pass | warn | fail + why>
|
|
333
|
-
C. What "see more" must repay: <the open loop the first body beat must answer>
|
|
334
|
-
|
|
335
|
-
II. Thesis the post will defend
|
|
336
|
-
A. One-sentence thesis: <the post's operating claim>
|
|
337
|
-
B. Reader being taught: <specific audience, not a broad persona>
|
|
338
|
-
C. Why this reader cares now: <timely pain, belief, or decision>
|
|
339
|
-
|
|
340
|
-
III. Operating model
|
|
341
|
-
A. Core equation or mechanism: <the model the post teaches>
|
|
342
|
-
B. Key definitions:
|
|
343
|
-
i. <term>: <plain definition + concrete examples>
|
|
344
|
-
ii. <term>: <plain definition + concrete examples>
|
|
345
|
-
|
|
346
|
-
IV. Body shape borrowed from posts that worked
|
|
347
|
-
A. Selected source template or no-template rationale: <source or rationale>
|
|
348
|
-
B. Source-message outline being adapted:
|
|
349
|
-
i. <source post + P1/P2/P3 branch sequence from the original message>
|
|
350
|
-
ii. <which original paragraph/line/phrase jobs matter most>
|
|
351
|
-
C. Working body pattern(s) being adapted:
|
|
352
|
-
i. <pattern name>: <beat order and why it works>
|
|
353
|
-
ii. <pattern name>: <beat order and why it works>
|
|
354
|
-
D. What gets borrowed:
|
|
355
|
-
i. <narrative job, sequence, transition, or proof order>
|
|
356
|
-
E. What must not be copied:
|
|
357
|
-
i. <source wording, creator-specific proof, joke, or context>
|
|
358
|
-
|
|
359
|
-
V. Narrative beats
|
|
360
|
-
A. Beat 1: <job, reader state before/after, example/proof>
|
|
361
|
-
i. Line shape or section label: <how it will appear>
|
|
362
|
-
ii. Concrete examples: <examples/numbers>
|
|
363
|
-
B. Beat 2: <job, reader state before/after, example/proof>
|
|
364
|
-
i. Line shape or section label: <how it will appear>
|
|
365
|
-
ii. Concrete examples: <examples/numbers>
|
|
366
|
-
C. Beat 3: <job, reader state before/after, example/proof>
|
|
367
|
-
i. Line shape or section label: <how it will appear>
|
|
368
|
-
ii. Concrete examples: <examples/numbers>
|
|
369
|
-
|
|
370
|
-
VI. Scan path and proof safety
|
|
371
|
-
A. Mobile scan path: <what skimmers learn from labels/numbers/close>
|
|
372
|
-
B. Proof claims:
|
|
373
|
-
i. <claim>: <source + public-safety status>
|
|
374
|
-
C. Abstractions to remove:
|
|
375
|
-
i. <abstract phrase> -> <concrete replacement>
|
|
376
|
-
D. Draft risks: <risk and how to avoid it>
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
Quality gate:
|
|
380
|
-
|
|
381
|
-
- The outline must explain the post before the draft exists.
|
|
382
|
-
- The outline must be useful to a reader who only scans the finished post.
|
|
383
|
-
- The outline must include proof claims and risk before prose.
|
|
384
|
-
- The outline must define any operating terms that could be misunderstood.
|
|
385
|
-
- The outline must use `I.`, `A.`, and `i.` hierarchy. A flat field list fails.
|
|
386
|
-
- If the post is adapting bodies that worked, the outline must name the source
|
|
387
|
-
message outline being adapted and the body pattern, including which original
|
|
388
|
-
paragraph/line/phrase jobs transfer and what beat order, proof order, or
|
|
389
|
-
transition logic is being borrowed.
|
|
390
|
-
- If the post is a field guide, the narrative beats must show the hierarchy
|
|
391
|
-
before prose, such as best-to-worst, highest-to-lowest intent, or
|
|
392
|
-
source-to-outcome.
|
|
393
|
-
- If the outline cannot be made concrete, return to premise development.
|
|
394
|
-
|
|
395
111
|
## Premise Quality Gate
|
|
396
112
|
|
|
397
113
|
A premise can move to hook generation only when it passes all of these:
|
|
@@ -402,10 +118,7 @@ A premise can move to hook generation only when it passes all of these:
|
|
|
402
118
|
- `reader_value`: pass
|
|
403
119
|
- `credible_speaker`: pass
|
|
404
120
|
- `proof_safety`: pass
|
|
405
|
-
- `
|
|
406
|
-
- `template_fit`: pass or explicitly no-template
|
|
407
|
-
- `hook_to_body_repayment`: pass
|
|
408
|
-
- `pre_draft_narrative_outline`: pass
|
|
121
|
+
- `market_heat`: pass or explained
|
|
409
122
|
|
|
410
123
|
If any gate fails:
|
|
411
124
|
|
|
@@ -424,11 +137,8 @@ For each hook candidate, include:
|
|
|
424
137
|
- which tension it opens
|
|
425
138
|
- which reader value it implies
|
|
426
139
|
- whether the real scene appears in the first screen or shortly after
|
|
427
|
-
- source template or no-template rationale
|
|
428
|
-
- hook promise the body must repay
|
|
429
140
|
|
|
430
141
|
Reject hooks that are accurate but do not reveal the premise's tension or value.
|
|
431
|
-
Reject hooks that create a promise the selected viral-post outline cannot repay.
|
|
432
142
|
|
|
433
143
|
## Body Relationship
|
|
434
144
|
|
|
@@ -445,6 +155,5 @@ body outline:
|
|
|
445
155
|
7. close returns to the premise without summarizing
|
|
446
156
|
```
|
|
447
157
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
return to premise development.
|
|
158
|
+
If this outline cannot be filled without inventing proof, return to premise
|
|
159
|
+
development.
|
|
@@ -9,10 +9,31 @@ Prospeo supports search + import in the campaign builder flow.
|
|
|
9
9
|
## Provider Decision Tree
|
|
10
10
|
|
|
11
11
|
- Known account list or CSV: use `load_csv_domains` or `save_domain_filters`, then `search_prospeo`.
|
|
12
|
+
- Current LinkedIn job-post intent: use `search_harvest_jobs`, review the job artifact, then use `confirm_harvest_job_companies` with selected Harvest job IDs to create a `domainFilterId`; only then call `search_prospeo` for hiring stakeholders at those companies. Harvest jobs are the account source, not a people-search replacement.
|
|
12
13
|
- Company/account lookalikes: use `search_prospeo_companies`, review the account sample, then use `confirm_prospeo_company_accounts` with the returned `companySearchToken` to create a `domainFilterId`; only then call `search_prospeo` for people at those accounts. Account rows are not people leads yet.
|
|
13
14
|
- Person search with known filters: use `search_prospeo` directly.
|
|
14
15
|
- LinkedIn activity, content-source, or post-engagement intent: stay on Signal Discovery or Sales Nav, not Prospeo.
|
|
15
16
|
|
|
17
|
+
Current LinkedIn job-post account sourcing must follow:
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
search_harvest_jobs -> confirm_harvest_job_companies -> search_prospeo
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Use `search_harvest_jobs` when the user's account-source intent is current
|
|
24
|
+
LinkedIn job posts, for example "companies hiring Power BI developers in the US
|
|
25
|
+
this month." The search tool writes review artifacts and returns a token or
|
|
26
|
+
`mcp-harvest-job-search-token:*` reference. After reviewing selected jobs, call
|
|
27
|
+
`confirm_harvest_job_companies` with selected Harvest job IDs only. It resolves
|
|
28
|
+
real company website domains from selected job details and bounded
|
|
29
|
+
`/linkedin/company` fallback, then returns a `domainFilterId` for
|
|
30
|
+
`search_prospeo`.
|
|
31
|
+
|
|
32
|
+
Do not paste LinkedIn company URLs as domains. Do not detail-fetch every job row
|
|
33
|
+
by default; fetch details only for selected batches during confirmation. Use
|
|
34
|
+
Prospeo directly when the user wants broader volume, company attributes,
|
|
35
|
+
lookalikes, or people search without needing current LinkedIn job evidence.
|
|
36
|
+
|
|
16
37
|
Company/account lookalikes must follow:
|
|
17
38
|
|
|
18
39
|
```text
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
# LinkedIn Preview Rendering
|
|
2
|
-
|
|
3
|
-
This asset defines the required rendered-preview contract for create-post hook
|
|
4
|
-
research, hook candidate generation, gold-standard decomposition, and draft
|
|
5
|
-
validation.
|
|
6
|
-
|
|
7
|
-
Character budgets are only diagnostics. They are not the preview gate. A hook is
|
|
8
|
-
not studied, selected, or ready until its visible mobile and desktop blocks come
|
|
9
|
-
from `mcp__sellable__calculate_linkedin_hook_preview` or from a stricter
|
|
10
|
-
authenticated LinkedIn screenshot.
|
|
11
|
-
|
|
12
|
-
Do not let the LLM imagine wrapping. The normal path is a function call that
|
|
13
|
-
returns rendered mobile and desktop lines. HTML and PNG outputs from
|
|
14
|
-
`mcp__sellable__render_linkedin_post_preview` are optional visual QA artifacts,
|
|
15
|
-
not the primary interface.
|
|
16
|
-
|
|
17
|
-
## Rendering Basis
|
|
18
|
-
|
|
19
|
-
LinkedIn does not publish exact feed truncation rules, and rendering can vary by
|
|
20
|
-
surface, app version, device, media attachment, and account state. Use this
|
|
21
|
-
deterministic function as the MCP review gate for unpublished drafts.
|
|
22
|
-
|
|
23
|
-
Simple operating policy: judge the hook by the first 3 rendered lines. Use ~140
|
|
24
|
-
characters on mobile and ~210 characters on desktop as guardrails only. If the
|
|
25
|
-
3-line preview and the character guardrail disagree, trust the rendered lines.
|
|
26
|
-
|
|
27
|
-
Call:
|
|
28
|
-
|
|
29
|
-
```json
|
|
30
|
-
mcp__sellable__calculate_linkedin_hook_preview({
|
|
31
|
-
"postText": "<full post text or candidate hook block>",
|
|
32
|
-
"sourceLabel": "<draft id, hook id, or source label>",
|
|
33
|
-
"measurementMode": "browser"
|
|
34
|
-
})
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
When local Chrome is available, browser measurement is the preferred functional
|
|
38
|
-
basis because it asks the browser layout engine to wrap the text under the
|
|
39
|
-
contract. When Chrome is unavailable, the tool falls back to the deterministic
|
|
40
|
-
width model and must mark that basis.
|
|
41
|
-
|
|
42
|
-
Treat "see more" as a rendered-line problem first and a character-count problem
|
|
43
|
-
second. Observed LinkedIn screenshots show the current desktop feed behaving
|
|
44
|
-
like a first-3-rendered-lines clamp: a first line, a blank line, and a third
|
|
45
|
-
line can be all that appears before `... more`.
|
|
46
|
-
|
|
47
|
-
- review gate: first 3 rendered visual lines
|
|
48
|
-
- mobile feed: tighter because the text column is narrower
|
|
49
|
-
- desktop feed: more characters can fit per line, but still review line count
|
|
50
|
-
- posts with media may show fewer text lines before truncation
|
|
51
|
-
- blank lines and intentional separators consume visible preview lines
|
|
52
|
-
- device width, font scaling, app version, browser, and profile/page context can
|
|
53
|
-
move the cutoff
|
|
54
|
-
|
|
55
|
-
Because of that variation, never say a hook is guaranteed to render before
|
|
56
|
-
"see more." Say `pass`, `warn`, or `fail` under the rendered-preview contract,
|
|
57
|
-
and show the visible mobile and desktop blocks.
|
|
58
|
-
|
|
59
|
-
When an authenticated LinkedIn feed/composer/browser screenshot is available,
|
|
60
|
-
that screenshot is the strongest evidence. Still record the fields below so
|
|
61
|
-
future agents can compare candidates without redoing the visual inspection.
|
|
62
|
-
|
|
63
|
-
Observed public LinkedIn post text style for feed-style post pages:
|
|
64
|
-
|
|
65
|
-
```text
|
|
66
|
-
selector basis: p.attributed-text-segment-list__content
|
|
67
|
-
font family: -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue",
|
|
68
|
-
"Fira Sans", Ubuntu, "Oxygen Sans", Cantarell, "Droid Sans",
|
|
69
|
-
"Lucida Grande", Helvetica, Arial, sans-serif
|
|
70
|
-
font size: 14px
|
|
71
|
-
line height: 21px
|
|
72
|
-
font weight: 400
|
|
73
|
-
letter spacing: normal
|
|
74
|
-
white space: pre-wrap
|
|
75
|
-
overflow wrap: break-word
|
|
76
|
-
text color: rgba(0, 0, 0, 0.9)
|
|
77
|
-
mobile text width: 308px
|
|
78
|
-
desktop text width: 582px
|
|
79
|
-
review clamp: first 3 rendered text lines
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
The `review clamp` is not an official LinkedIn rule. It is the conservative
|
|
83
|
-
apples-to-apples region create-post must use when comparing hooks. Do not let a
|
|
84
|
-
desktop pass rescue a mobile fail.
|
|
85
|
-
|
|
86
|
-
## Required Rendering Record
|
|
87
|
-
|
|
88
|
-
Every shortlisted source hook, adapted hook block, generated hook candidate, and
|
|
89
|
-
selected hook must include a `renderedPreview` record:
|
|
90
|
-
|
|
91
|
-
```text
|
|
92
|
-
renderedPreview:
|
|
93
|
-
basis: linkedin_rendering_rule_function | authenticated_linkedin_screenshot | manual_user_source
|
|
94
|
-
cssContractVersion: linkedin-preview-rendering/v2
|
|
95
|
-
mobile:
|
|
96
|
-
textWidthPx: 308
|
|
97
|
-
fontSizePx: 14
|
|
98
|
-
lineHeightPx: 21
|
|
99
|
-
clampLines: 3
|
|
100
|
-
charGuardrail: 140
|
|
101
|
-
measurementBasis: local_chrome_browser_layout | estimated_width_model
|
|
102
|
-
visibleTextBlock: <literal first 3 rendered lines>
|
|
103
|
-
renderedLines:
|
|
104
|
-
- <line 1 exactly as wrapped>
|
|
105
|
-
- <line 2 exactly as wrapped>
|
|
106
|
-
- <line 3 exactly as wrapped>
|
|
107
|
-
lineCountBeforeClamp: <number>
|
|
108
|
-
blankLinesBeforeClamp: <number>
|
|
109
|
-
corePainProofOrCuriosityVisible: true | false
|
|
110
|
-
corePointVisible: true | false
|
|
111
|
-
intentionalOpenLoop: true | false
|
|
112
|
-
specificClickQuestionVisible: true | false
|
|
113
|
-
payoffPlannedImmediatelyAfterClamp: true | false
|
|
114
|
-
seeMoreClickReason: <why a reader would click see more>
|
|
115
|
-
seeMoreRisk: pass | warn | fail
|
|
116
|
-
desktop:
|
|
117
|
-
textWidthPx: 582
|
|
118
|
-
fontSizePx: 14
|
|
119
|
-
lineHeightPx: 21
|
|
120
|
-
clampLines: 3
|
|
121
|
-
charGuardrail: 210
|
|
122
|
-
measurementBasis: local_chrome_browser_layout | estimated_width_model
|
|
123
|
-
visibleTextBlock: <literal first 3 rendered lines>
|
|
124
|
-
renderedLines:
|
|
125
|
-
- <line 1 exactly as wrapped>
|
|
126
|
-
- <line 2 exactly as wrapped>
|
|
127
|
-
- <line 3 exactly as wrapped>
|
|
128
|
-
lineCountBeforeClamp: <number>
|
|
129
|
-
blankLinesBeforeClamp: <number>
|
|
130
|
-
corePainProofOrCuriosityVisible: true | false
|
|
131
|
-
corePointVisible: true | false
|
|
132
|
-
seeMoreRisk: pass | warn | fail
|
|
133
|
-
diagnostics:
|
|
134
|
-
charCount: <number>
|
|
135
|
-
charCountIncludingNewlines: <number>
|
|
136
|
-
firstLineChars: <number>
|
|
137
|
-
firstTwoPhysicalLinesChars: <number>
|
|
138
|
-
longestNonblankLineChars: <number>
|
|
139
|
-
blankLineVisualRisk: none | low | medium | high
|
|
140
|
-
pointAfterMobileClamp: true | false
|
|
141
|
-
openLoopType: none | hidden_payoff | contradiction | proof_gap | workflow_reveal | asset_reveal | story_gap
|
|
142
|
-
rewriteIfTruncated: <short fallback>
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
If a host cannot produce literal wrapped line blocks from
|
|
146
|
-
`calculate_linkedin_hook_preview`, return `blocked` or `needs_revision`; do not
|
|
147
|
-
claim the hook passed preview validation from character counts alone.
|
|
148
|
-
|
|
149
|
-
## Study Rules
|
|
150
|
-
|
|
151
|
-
For source-post research:
|
|
152
|
-
|
|
153
|
-
- Render the exact visible opening from full text when full text is available.
|
|
154
|
-
- If only a search preview is available, render only the preview text and set
|
|
155
|
-
`basis: manual_user_source` or record `sourceTextBasis: search_preview`.
|
|
156
|
-
- Lower confidence when the search preview is cut off or the body is
|
|
157
|
-
unavailable.
|
|
158
|
-
- Extract hook lessons from the rendered first-screen experience, not from the
|
|
159
|
-
full post in isolation.
|
|
160
|
-
|
|
161
|
-
For generated hooks:
|
|
162
|
-
|
|
163
|
-
- Generate the hook from the selected premise first.
|
|
164
|
-
- Render the hook for mobile and desktop before scoring it.
|
|
165
|
-
- Score the rendered first-screen click reason before scoring cleverness.
|
|
166
|
-
- If the goal is see-more clicks, the hook may intentionally hide the payoff
|
|
167
|
-
after the mobile clamp, but the visible block must create a specific question
|
|
168
|
-
the target reader wants answered.
|
|
169
|
-
- Rewrite any candidate whose real point appears after the mobile clamp unless
|
|
170
|
-
that point is the planned payoff for an intentional open loop.
|
|
171
|
-
|
|
172
|
-
## Pass, Warn, Fail
|
|
173
|
-
|
|
174
|
-
Use these rendered gates:
|
|
175
|
-
|
|
176
|
-
- `pass`: the mobile rendered preview shows the pain, proof, or curiosity by the
|
|
177
|
-
end of the first 3 rendered lines, and either the core point is
|
|
178
|
-
understandable without opening "see more" or an intentional open loop creates
|
|
179
|
-
a specific click question with an immediate planned payoff.
|
|
180
|
-
- `warn`: the mobile rendered preview creates useful curiosity but the core
|
|
181
|
-
point or click question is slightly softened by wrapping, blank-line rhythm,
|
|
182
|
-
or one missing context word. A compact fallback is required.
|
|
183
|
-
- `fail`: the hook's real point appears after the first 3 mobile rendered lines,
|
|
184
|
-
the visible open loop is vague, the first rendered line is generic setup,
|
|
185
|
-
blank lines consume the preview before the reader sees the point, or desktop
|
|
186
|
-
fit is the only reason it looks good.
|
|
187
|
-
|
|
188
|
-
A draft cannot be `ready` when the selected hook has:
|
|
189
|
-
|
|
190
|
-
- no `renderedPreview`
|
|
191
|
-
- `mobile.seeMoreRisk: fail`
|
|
192
|
-
- `mobile.corePainProofOrCuriosityVisible: false`
|
|
193
|
-
- `mobile.corePointVisible: false` unless `mobile.intentionalOpenLoop: true`,
|
|
194
|
-
`mobile.specificClickQuestionVisible: true`, and
|
|
195
|
-
`mobile.payoffPlannedImmediatelyAfterClamp: true`
|
|
196
|
-
- `pointAfterMobileClamp: true` unless the point after the clamp is the
|
|
197
|
-
intentional payoff for a specific open loop
|
|
198
|
-
|
|
199
|
-
## Report Format
|
|
200
|
-
|
|
201
|
-
Research reports must show rendered preview blocks for the best examples and
|
|
202
|
-
recommended draft directions:
|
|
203
|
-
|
|
204
|
-
```text
|
|
205
|
-
Rendered preview:
|
|
206
|
-
mobile:
|
|
207
|
-
<line 1>
|
|
208
|
-
<line 2>
|
|
209
|
-
<line 3>
|
|
210
|
-
|
|
211
|
-
desktop:
|
|
212
|
-
<line 1>
|
|
213
|
-
<line 2>
|
|
214
|
-
<line 3>
|
|
215
|
-
|
|
216
|
-
verdict: pass | warn | fail
|
|
217
|
-
why: <what is visible before the fold>
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
Do not say "it fits on mobile" without showing what the mobile reader actually
|
|
221
|
-
sees.
|