@sellable/mcp 0.1.255 → 0.1.257
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/api.d.ts +3 -0
- package/dist/api.js +24 -13
- package/dist/index-dev.js +0 -0
- package/dist/index.js +0 -0
- package/dist/server.js +13 -7
- package/dist/tools/campaigns.d.ts +41 -0
- package/dist/tools/campaigns.js +22 -3
- package/dist/tools/csv-dnc.d.ts +0 -36
- package/dist/tools/csv-dnc.js +2 -94
- package/dist/tools/engage-discovery.d.ts +21 -0
- package/dist/tools/engage-discovery.js +136 -9
- package/dist/tools/leads.d.ts +16 -214
- package/dist/tools/leads.js +1 -39
- package/dist/tools/registry.d.ts +514 -606
- package/dist/tools/tables.d.ts +53 -2
- package/dist/tools/tables.js +78 -0
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +0 -6
- package/skills/create-campaign-v2/references/filter-leads.md +0 -2
- package/skills/create-campaign-v2/references/lead-validation-preview.md +0 -2
- package/skills/create-campaign-v2/references/step-13-import-leads.md +1 -3
- package/skills/create-post/SKILL.md +67 -21
- package/skills/create-post/references/gold-standard-post-pack.md +11 -0
- package/skills/create-post/references/hook-research-playbook.md +205 -15
- package/skills/create-post/references/linkedin-preview-rendering.md +163 -0
- package/skills/create-post/references/post-file-contract.md +12 -0
- package/skills/create-post/references/post-validation.md +101 -14
- package/skills/find-leads/SKILL.md +0 -6
- package/skills/research/config.json +9 -0
|
@@ -28,10 +28,11 @@ Worker owns:
|
|
|
28
28
|
- tracked-person post fetches
|
|
29
29
|
- full-text matching by URL/activity ID
|
|
30
30
|
- duplicate removal
|
|
31
|
+
- follower-band and reach-normalized signal scoring
|
|
31
32
|
- lead-magnet, giveaway, engagement-bait, and off-voice filtering
|
|
32
33
|
- market belief mapping across kept and rejected examples
|
|
33
34
|
- premise input extraction: real scenes, observed tensions, reader value, proof gaps
|
|
34
|
-
- hook opening measurement
|
|
35
|
+
- rendered hook opening measurement
|
|
35
36
|
- exact phrase-pattern extraction
|
|
36
37
|
- body-structure extraction
|
|
37
38
|
- rejected-example notes
|
|
@@ -58,7 +59,8 @@ Research packet:
|
|
|
58
59
|
- exact phrase patterns: max 20
|
|
59
60
|
- body patterns: max 8
|
|
60
61
|
- source URLs and author profile URLs
|
|
61
|
-
-
|
|
62
|
+
- reach-normalized signal notes
|
|
63
|
+
- rendered preview records
|
|
62
64
|
- confidence gaps
|
|
63
65
|
- save recommendations
|
|
64
66
|
```
|
|
@@ -74,6 +76,13 @@ Use `mcp__sellable__search_engagement_posts` with practical constraints:
|
|
|
74
76
|
|
|
75
77
|
- explicit `maxAgeDays: 120` by default so research covers the past 30-120 days, not only this week's posts
|
|
76
78
|
- tighten to 30-60 days for trend-sensitive topics; widen only when the topic has low volume
|
|
79
|
+
- when the user gives a follower range, pass it as `targetFollowerMin` and
|
|
80
|
+
`targetFollowerMax` so the tool can expose reach-normalized signals and
|
|
81
|
+
prioritize comparable creators
|
|
82
|
+
- if a source hook looks promising but follower count is missing, use
|
|
83
|
+
`mcp__sellable__fetch_linkedin_profile` on a bounded shortlist before calling
|
|
84
|
+
the source a keeper; if profile fetch is unavailable or too slow, mark
|
|
85
|
+
`follower_count_unavailable`
|
|
77
86
|
- high enough engagement to matter
|
|
78
87
|
- narrow enough to match the idea
|
|
79
88
|
- enough result depth to see whether a creator has repeated winners, not just one viral outlier
|
|
@@ -82,14 +91,19 @@ Record every keyword, filter, search window, page, and result count.
|
|
|
82
91
|
|
|
83
92
|
## Weighted Signals
|
|
84
93
|
|
|
85
|
-
Rank source posts with a weighted signal view. Do not sort by total engagement
|
|
94
|
+
Rank source posts with a weighted signal view. Do not sort by total engagement
|
|
95
|
+
alone. Use the numeric score to decide which sources deserve study; do not let
|
|
96
|
+
the number choose the final hook by itself.
|
|
86
97
|
|
|
87
98
|
Use this scoring shape:
|
|
88
99
|
|
|
89
100
|
```text
|
|
90
101
|
hook_score =
|
|
91
102
|
topic_fit
|
|
103
|
+
+ rendered_mobile_preview_strength
|
|
92
104
|
+ hook_clarity
|
|
105
|
+
+ content_pattern_replicability
|
|
106
|
+
+ reach_adjusted_evidence
|
|
93
107
|
+ creator_repeat_success
|
|
94
108
|
+ repost_share_strength
|
|
95
109
|
+ comment_quality
|
|
@@ -107,6 +121,135 @@ Guidance:
|
|
|
107
121
|
- If share or repost data is unavailable, record `repost_data_unavailable` instead of inventing it.
|
|
108
122
|
- Prefer creators with repeated high-performing posts in the same lane over one-off viral posts.
|
|
109
123
|
|
|
124
|
+
## Reach-Normalized Hook Scoring
|
|
125
|
+
|
|
126
|
+
Raw engagement is not the clearest signal when source creators have wildly
|
|
127
|
+
different audience sizes. A post from a 100k+ follower creator can win on
|
|
128
|
+
distribution even when the hook is ordinary. A post from a creator near the
|
|
129
|
+
user's follower range that overperforms is a clearer signal that LinkedIn and
|
|
130
|
+
readers rewarded the hook/premise.
|
|
131
|
+
|
|
132
|
+
This calculation is a source-quality filter, not the final creative decision.
|
|
133
|
+
After reach is controlled, the LLM still chooses the hooks to steal based on the
|
|
134
|
+
visible hook, rendered first-screen promise, content pattern, premise fit, and
|
|
135
|
+
whether the idea can carry without the source creator's distribution.
|
|
136
|
+
|
|
137
|
+
When the user gives a target range, default to that range. For example, if the
|
|
138
|
+
user says "8k to 20k followers," call `mcp__sellable__search_engagement_posts`
|
|
139
|
+
with:
|
|
140
|
+
|
|
141
|
+
```text
|
|
142
|
+
targetFollowerMin: 8000
|
|
143
|
+
targetFollowerMax: 20000
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
If the user gives no range, use the user's known follower count from memory or
|
|
147
|
+
ask only when the decision depends on it. If no follower count is available, use
|
|
148
|
+
raw engagement as a fallback and mark `target_follower_band_unknown`.
|
|
149
|
+
|
|
150
|
+
For every shortlisted source post, record:
|
|
151
|
+
|
|
152
|
+
- `authorFollowerCount`
|
|
153
|
+
- `targetFollowerBand`
|
|
154
|
+
- `followerBandFit`: `in_target_band`, `below_target_band`,
|
|
155
|
+
`above_target_band`, or `unknown`
|
|
156
|
+
- `engagementPer1kFollowers`
|
|
157
|
+
- `weightedEngagementPer1kFollowers`
|
|
158
|
+
- `reachAdjustedScore`
|
|
159
|
+
- `creatorBaselineMedianEngagement` when repeated posts from that creator are
|
|
160
|
+
available
|
|
161
|
+
- `baselineLift`: this post's engagement divided by the creator's recent median
|
|
162
|
+
engagement in the same lane, or `creator_baseline_unavailable`
|
|
163
|
+
- `confidence`: `high`, `medium`, or `low`
|
|
164
|
+
- `normalizationNotes`
|
|
165
|
+
|
|
166
|
+
Use this Harvest-compatible calculation when follower counts are available:
|
|
167
|
+
|
|
168
|
+
```text
|
|
169
|
+
weightedEngagement =
|
|
170
|
+
likes
|
|
171
|
+
+ (comments * 4)
|
|
172
|
+
+ (shares * 12)
|
|
173
|
+
|
|
174
|
+
engagementPer1kFollowers =
|
|
175
|
+
totalEngagement / authorFollowerCount * 1000
|
|
176
|
+
|
|
177
|
+
weightedEngagementPer1kFollowers =
|
|
178
|
+
weightedEngagement / authorFollowerCount * 1000
|
|
179
|
+
|
|
180
|
+
reachPenaltyMultiplier =
|
|
181
|
+
1.00 when in target follower band
|
|
182
|
+
0.75 when below target band
|
|
183
|
+
0.65 when above target band but <= 2x target max
|
|
184
|
+
0.35 when above target band but <= 5x target max
|
|
185
|
+
0.15 when above target band and > 5x target max
|
|
186
|
+
0.40 when follower count is unknown
|
|
187
|
+
|
|
188
|
+
reachAdjustedScore =
|
|
189
|
+
weightedEngagementPer1kFollowers * reachPenaltyMultiplier
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
When repeated posts from the same creator are available, calculate:
|
|
193
|
+
|
|
194
|
+
```text
|
|
195
|
+
creatorBaselineMedianEngagement =
|
|
196
|
+
median weightedEngagement across recent same-lane posts
|
|
197
|
+
|
|
198
|
+
baselineLift =
|
|
199
|
+
post weightedEngagement / creatorBaselineMedianEngagement
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Use this scoring shape when deciding which hooks to study:
|
|
203
|
+
|
|
204
|
+
```text
|
|
205
|
+
hook_score =
|
|
206
|
+
topic_fit
|
|
207
|
+
+ rendered_mobile_preview_strength
|
|
208
|
+
+ hook_clarity
|
|
209
|
+
+ same_follower_band_bonus
|
|
210
|
+
+ weighted_engagement_per_1k_followers
|
|
211
|
+
+ creator_baseline_lift
|
|
212
|
+
+ repost_share_strength
|
|
213
|
+
+ substantive_comment_quality
|
|
214
|
+
+ creator_repeat_success
|
|
215
|
+
- celebrity_reach_penalty
|
|
216
|
+
- tiny_sample_penalty
|
|
217
|
+
- lead_magnet_penalty
|
|
218
|
+
- engagement_bait_penalty
|
|
219
|
+
- off_voice_penalty
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Rules:
|
|
223
|
+
|
|
224
|
+
- Prefer in-band creators when the hook is strong and the engagement is real.
|
|
225
|
+
- Use near-band creators as secondary evidence.
|
|
226
|
+
- Penalize creators far above the target range, especially accounts above 5x
|
|
227
|
+
the target max or above 100k followers when the target range is 8k-20k.
|
|
228
|
+
- Do not automatically reject large-account posts; they can still teach body
|
|
229
|
+
structure, topic heat, or category language. Do not treat them as primary hook
|
|
230
|
+
proof unless they also overperform their creator baseline.
|
|
231
|
+
- Large-account hooks can be selected only when the hook carries without the
|
|
232
|
+
creator: the rendered mobile opening is strong, the premise is reusable by the
|
|
233
|
+
user, the body pattern does not depend on celebrity authority, and the source
|
|
234
|
+
either beats baseline or has unusually high reach-adjusted quality after the
|
|
235
|
+
penalty.
|
|
236
|
+
- Do not overvalue tiny-account anomalies. Very high engagement per follower
|
|
237
|
+
with low absolute engagement is interesting but lower confidence.
|
|
238
|
+
- When follower data is unavailable, do not invent it. Mark
|
|
239
|
+
`follower_count_unavailable`, lower confidence, and rely more on creator repeat
|
|
240
|
+
evidence, repost/share strength, comment quality, and rendered preview quality.
|
|
241
|
+
- A source hook is strongest when it is in/near the target follower band, has
|
|
242
|
+
real absolute engagement, beats the creator's apparent baseline, has
|
|
243
|
+
share/comment quality, and passes rendered mobile preview.
|
|
244
|
+
|
|
245
|
+
Final hook selection must explain both:
|
|
246
|
+
|
|
247
|
+
- `whyTheHookCarries`: the visible words, specificity, tension, and first-screen
|
|
248
|
+
promise that work independent of reach
|
|
249
|
+
- `whyTheReachEvidenceIsTrustworthy`: follower-band fit, reach-adjusted score,
|
|
250
|
+
baseline lift, share/comment quality, or why a large-account example is only
|
|
251
|
+
secondary pattern evidence
|
|
252
|
+
|
|
110
253
|
Penalize lead-magnet and engagement-bait mechanics unless the user explicitly asks for that style:
|
|
111
254
|
|
|
112
255
|
- `comment "template"` / `comment "guide"` / `comment "playbook"`
|
|
@@ -198,24 +341,48 @@ Measure the visible opening for every shortlisted source post before extracting
|
|
|
198
341
|
the hook pattern. This makes the study useful for LinkedIn, not just generally
|
|
199
342
|
"good writing."
|
|
200
343
|
|
|
201
|
-
LinkedIn does not publish exact
|
|
202
|
-
|
|
344
|
+
Use `references/linkedin-preview-rendering.md`. LinkedIn does not publish exact
|
|
345
|
+
"see more" cutoff rules. Character counts are diagnostics only. A source post
|
|
346
|
+
or generated hook is not properly studied until it has a rendered mobile and
|
|
347
|
+
desktop preview record.
|
|
348
|
+
|
|
349
|
+
Default deterministic renderer for unpublished drafts and research comparison:
|
|
203
350
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
351
|
+
```text
|
|
352
|
+
cssContractVersion: linkedin-preview-rendering/v1
|
|
353
|
+
font size: 14px
|
|
354
|
+
line height: 21px
|
|
355
|
+
white space: pre-wrap
|
|
356
|
+
overflow wrap: break-word
|
|
357
|
+
mobile text width: 308px
|
|
358
|
+
desktop text width: 582px
|
|
359
|
+
review clamp: first 3 rendered text lines
|
|
360
|
+
```
|
|
211
361
|
|
|
212
|
-
|
|
213
|
-
|
|
362
|
+
Authenticated LinkedIn feed/composer screenshots are stronger evidence when
|
|
363
|
+
available. If a screenshot is used, still record the wrapped lines and verdicts
|
|
364
|
+
below so another agent can compare hooks without re-opening LinkedIn.
|
|
365
|
+
|
|
366
|
+
Desktop preview has more room, but never let desktop fit compensate for a
|
|
367
|
+
mobile `fail`.
|
|
214
368
|
|
|
215
369
|
For each source, record:
|
|
216
370
|
|
|
217
371
|
- `sourceTextBasis`: `full_text`, `search_preview`, or `manual_user_source`
|
|
218
372
|
- `openingTextUsed`
|
|
373
|
+
- `renderedPreview`
|
|
374
|
+
- `cssContractVersion`
|
|
375
|
+
- `mobileRenderedPreviewBlock`
|
|
376
|
+
- `desktopRenderedPreviewBlock`
|
|
377
|
+
- `mobileRenderedLines`
|
|
378
|
+
- `desktopRenderedLines`
|
|
379
|
+
- `mobileRenderedLineCount`
|
|
380
|
+
- `desktopRenderedLineCount`
|
|
381
|
+
- `corePainProofOrCuriosityVisibleMobile`
|
|
382
|
+
- `corePainProofOrCuriosityVisibleDesktop`
|
|
383
|
+
- `corePointVisibleMobile`
|
|
384
|
+
- `corePointVisibleDesktop`
|
|
385
|
+
- `pointAfterMobileClamp`
|
|
219
386
|
- `charCountIncludingNewlines`
|
|
220
387
|
- `physicalLineCount`
|
|
221
388
|
- `contentLineCount`
|
|
@@ -228,11 +395,25 @@ For each source, record:
|
|
|
228
395
|
- `desktopPreviewBudget`: `pass`, `warn`, or `fail`
|
|
229
396
|
- `blankLineVisualRisk`
|
|
230
397
|
- `corePointBeforeLikelyTruncation`
|
|
398
|
+
- `renderedPreviewVerdict`: `pass`, `warn`, or `fail`
|
|
231
399
|
|
|
232
400
|
If only a search preview is available, do not pretend the opening is complete.
|
|
233
401
|
Record `sourceTextBasis: search_preview` and lower confidence when the hook
|
|
234
402
|
appears cut off or body context is unavailable.
|
|
235
403
|
|
|
404
|
+
Pass/warn/fail is based on rendered output:
|
|
405
|
+
|
|
406
|
+
- `pass`: the mobile rendered preview shows the pain, proof, or curiosity by
|
|
407
|
+
the end of the first 3 rendered lines, and the core point is understandable
|
|
408
|
+
without opening "see more".
|
|
409
|
+
- `warn`: the mobile rendered preview creates useful curiosity but the core
|
|
410
|
+
point is slightly softened by wrapping, blank-line rhythm, or one missing
|
|
411
|
+
context word. A compact fallback is required.
|
|
412
|
+
- `fail`: the hook's real point appears after the first 3 mobile rendered
|
|
413
|
+
lines, the first rendered line is generic setup, blank lines consume the
|
|
414
|
+
preview before the reader sees the point, or desktop fit is the only reason it
|
|
415
|
+
looks good.
|
|
416
|
+
|
|
236
417
|
## Hook Extraction
|
|
237
418
|
|
|
238
419
|
Extract structure and reusable language patterns, not copied prose. The goal is
|
|
@@ -245,10 +426,13 @@ For each shortlisted source post, record:
|
|
|
245
426
|
- URL
|
|
246
427
|
- author
|
|
247
428
|
- author profile URL when available
|
|
429
|
+
- author follower count and follower-band fit when available
|
|
248
430
|
- engagement totals and available likes/comments/shares breakdown
|
|
431
|
+
- reach-normalized metrics: engagement per 1k followers, weighted engagement
|
|
432
|
+
per 1k followers, reach-adjusted score, baseline lift, and confidence
|
|
249
433
|
- creator repeat evidence
|
|
250
434
|
- visible hook text or preview
|
|
251
|
-
-
|
|
435
|
+
- rendered preview fields from the section above
|
|
252
436
|
- hook mechanism
|
|
253
437
|
- exact hook language patterns: reusable words, phrase shapes, contrast forms,
|
|
254
438
|
sentence shapes, and transition moves
|
|
@@ -258,10 +442,16 @@ For each shortlisted source post, record:
|
|
|
258
442
|
- proof/story dependency
|
|
259
443
|
- lead magnet or engagement bait penalty
|
|
260
444
|
- weighted signal notes
|
|
445
|
+
- reach-normalized signal notes
|
|
261
446
|
- replicability score
|
|
262
447
|
- track person recommendation: `yes`, `no`, or `ask_user`
|
|
263
448
|
- tracking reason when recommended
|
|
264
449
|
|
|
450
|
+
Do not call a source hook a keeper because the full text is strong if the
|
|
451
|
+
rendered mobile opening is weak. Study what a LinkedIn reader sees before
|
|
452
|
+
"see more"; the body structure can still be useful, but the hook should not be
|
|
453
|
+
copied into the hook pattern set.
|
|
454
|
+
|
|
265
455
|
## Specific Language Extraction
|
|
266
456
|
|
|
267
457
|
For each keeper, extract the source's specific language mechanics in this
|
|
@@ -0,0 +1,163 @@
|
|
|
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 it has been rendered through this contract
|
|
9
|
+
or through a stricter authenticated LinkedIn screenshot.
|
|
10
|
+
|
|
11
|
+
## Rendering Basis
|
|
12
|
+
|
|
13
|
+
LinkedIn does not publish exact feed truncation rules, and rendering can vary by
|
|
14
|
+
surface, app version, device, media attachment, and account state. Use this
|
|
15
|
+
deterministic renderer as the MCP review gate for unpublished drafts.
|
|
16
|
+
|
|
17
|
+
When an authenticated LinkedIn feed/composer/browser screenshot is available,
|
|
18
|
+
that screenshot is the strongest evidence. Still record the fields below so
|
|
19
|
+
future agents can compare candidates without redoing the visual inspection.
|
|
20
|
+
|
|
21
|
+
Observed public LinkedIn post text style for feed-style post pages:
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
selector basis: p.attributed-text-segment-list__content
|
|
25
|
+
font family: -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue",
|
|
26
|
+
"Fira Sans", Ubuntu, "Oxygen Sans", Cantarell, "Droid Sans",
|
|
27
|
+
"Lucida Grande", Helvetica, Arial, sans-serif
|
|
28
|
+
font size: 14px
|
|
29
|
+
line height: 21px
|
|
30
|
+
font weight: 400
|
|
31
|
+
letter spacing: normal
|
|
32
|
+
white space: pre-wrap
|
|
33
|
+
overflow wrap: break-word
|
|
34
|
+
text color: rgba(0, 0, 0, 0.9)
|
|
35
|
+
mobile text width: 308px
|
|
36
|
+
desktop text width: 582px
|
|
37
|
+
review clamp: first 3 rendered text lines
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The `review clamp` is not an official LinkedIn rule. It is the conservative
|
|
41
|
+
apples-to-apples region create-post must use when comparing hooks. Do not let a
|
|
42
|
+
desktop pass rescue a mobile fail.
|
|
43
|
+
|
|
44
|
+
## Required Rendering Record
|
|
45
|
+
|
|
46
|
+
Every shortlisted source hook, adapted hook block, generated hook candidate, and
|
|
47
|
+
selected hook must include a `renderedPreview` record:
|
|
48
|
+
|
|
49
|
+
```text
|
|
50
|
+
renderedPreview:
|
|
51
|
+
basis: linkedin_css_contract | authenticated_linkedin_screenshot | manual_user_source
|
|
52
|
+
cssContractVersion: linkedin-preview-rendering/v1
|
|
53
|
+
mobile:
|
|
54
|
+
textWidthPx: 308
|
|
55
|
+
fontSizePx: 14
|
|
56
|
+
lineHeightPx: 21
|
|
57
|
+
visibleTextBlock: <literal first rendered review-clamp block>
|
|
58
|
+
renderedLines:
|
|
59
|
+
- <line 1 exactly as wrapped>
|
|
60
|
+
- <line 2 exactly as wrapped>
|
|
61
|
+
- <line 3 exactly as wrapped>
|
|
62
|
+
lineCountBeforeClamp: <number>
|
|
63
|
+
blankLinesBeforeClamp: <number>
|
|
64
|
+
corePainProofOrCuriosityVisible: true | false
|
|
65
|
+
corePointVisible: true | false
|
|
66
|
+
seeMoreRisk: pass | warn | fail
|
|
67
|
+
screenshotPath: <optional local path>
|
|
68
|
+
desktop:
|
|
69
|
+
textWidthPx: 582
|
|
70
|
+
fontSizePx: 14
|
|
71
|
+
lineHeightPx: 21
|
|
72
|
+
visibleTextBlock: <literal first rendered review-clamp block>
|
|
73
|
+
renderedLines:
|
|
74
|
+
- <line 1 exactly as wrapped>
|
|
75
|
+
- <line 2 exactly as wrapped>
|
|
76
|
+
- <line 3 exactly as wrapped>
|
|
77
|
+
lineCountBeforeClamp: <number>
|
|
78
|
+
blankLinesBeforeClamp: <number>
|
|
79
|
+
corePainProofOrCuriosityVisible: true | false
|
|
80
|
+
corePointVisible: true | false
|
|
81
|
+
seeMoreRisk: pass | warn | fail
|
|
82
|
+
screenshotPath: <optional local path>
|
|
83
|
+
diagnostics:
|
|
84
|
+
charCount: <number>
|
|
85
|
+
charCountIncludingNewlines: <number>
|
|
86
|
+
firstLineChars: <number>
|
|
87
|
+
firstTwoPhysicalLinesChars: <number>
|
|
88
|
+
longestNonblankLineChars: <number>
|
|
89
|
+
blankLineVisualRisk: none | low | medium | high
|
|
90
|
+
pointAfterMobileClamp: true | false
|
|
91
|
+
rewriteIfTruncated: <short fallback>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
If a host cannot produce screenshots, it must still produce the literal wrapped
|
|
95
|
+
line blocks using the CSS contract. If it cannot produce either screenshots or
|
|
96
|
+
literal line wraps, return `blocked` or `needs_revision`; do not claim the hook
|
|
97
|
+
passed preview validation from character counts alone.
|
|
98
|
+
|
|
99
|
+
## Study Rules
|
|
100
|
+
|
|
101
|
+
For source-post research:
|
|
102
|
+
|
|
103
|
+
- Render the exact visible opening from full text when full text is available.
|
|
104
|
+
- If only a search preview is available, render only the preview text and set
|
|
105
|
+
`basis: manual_user_source` or record `sourceTextBasis: search_preview`.
|
|
106
|
+
- Lower confidence when the search preview is cut off or the body is
|
|
107
|
+
unavailable.
|
|
108
|
+
- Extract hook lessons from the rendered first-screen experience, not from the
|
|
109
|
+
full post in isolation.
|
|
110
|
+
|
|
111
|
+
For generated hooks:
|
|
112
|
+
|
|
113
|
+
- Generate the hook from the selected premise first.
|
|
114
|
+
- Render the hook for mobile and desktop before scoring it.
|
|
115
|
+
- Score the rendered first-screen promise before scoring cleverness.
|
|
116
|
+
- Rewrite any candidate whose real point appears after the mobile clamp.
|
|
117
|
+
|
|
118
|
+
## Pass, Warn, Fail
|
|
119
|
+
|
|
120
|
+
Use these rendered gates:
|
|
121
|
+
|
|
122
|
+
- `pass`: the mobile rendered preview shows the pain, proof, or curiosity by the
|
|
123
|
+
end of the first 3 rendered lines, and the core point is understandable
|
|
124
|
+
without opening "see more".
|
|
125
|
+
- `warn`: the mobile rendered preview creates useful curiosity but the core
|
|
126
|
+
point is slightly softened by wrapping, blank-line rhythm, or one missing
|
|
127
|
+
context word. A compact fallback is required.
|
|
128
|
+
- `fail`: the hook's real point appears after the first 3 mobile rendered lines,
|
|
129
|
+
the first rendered line is generic setup, blank lines consume the preview
|
|
130
|
+
before the reader sees the point, or desktop fit is the only reason it looks
|
|
131
|
+
good.
|
|
132
|
+
|
|
133
|
+
A draft cannot be `ready` when the selected hook has:
|
|
134
|
+
|
|
135
|
+
- no `renderedPreview`
|
|
136
|
+
- `mobile.seeMoreRisk: fail`
|
|
137
|
+
- `mobile.corePainProofOrCuriosityVisible: false`
|
|
138
|
+
- `mobile.corePointVisible: false`
|
|
139
|
+
- `pointAfterMobileClamp: true`
|
|
140
|
+
|
|
141
|
+
## Report Format
|
|
142
|
+
|
|
143
|
+
Research reports must show rendered preview blocks for the best examples and
|
|
144
|
+
recommended draft directions:
|
|
145
|
+
|
|
146
|
+
```text
|
|
147
|
+
Rendered preview:
|
|
148
|
+
mobile:
|
|
149
|
+
<line 1>
|
|
150
|
+
<line 2>
|
|
151
|
+
<line 3>
|
|
152
|
+
|
|
153
|
+
desktop:
|
|
154
|
+
<line 1>
|
|
155
|
+
<line 2>
|
|
156
|
+
<line 3>
|
|
157
|
+
|
|
158
|
+
verdict: pass | warn | fail
|
|
159
|
+
why: <what is visible before the fold>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Do not say "it fits on mobile" without showing what the mobile reader actually
|
|
163
|
+
sees.
|
|
@@ -59,10 +59,19 @@ Hook research files must preserve:
|
|
|
59
59
|
- source post URLs
|
|
60
60
|
- author/profile URLs
|
|
61
61
|
- engagement totals
|
|
62
|
+
- author follower counts when available, target follower band, follower-band
|
|
63
|
+
fit, engagement per 1k followers, weighted engagement per 1k followers,
|
|
64
|
+
reach penalty multiplier, reach-adjusted score, baseline lift when available,
|
|
65
|
+
why the hook carries independent of creator reach, and normalization
|
|
66
|
+
confidence notes
|
|
62
67
|
- full-text availability
|
|
63
68
|
- source hook preview measurements, including text basis, char count including
|
|
64
69
|
newlines, physical/content line counts, longest nonblank line, blank-line
|
|
65
70
|
visual risk, and mobile/desktop preview budget status
|
|
71
|
+
- rendered preview records for every kept source hook and adapted hook block,
|
|
72
|
+
including literal mobile/desktop preview blocks, rendered line wraps, render
|
|
73
|
+
basis, CSS contract version, text widths, first-screen promise visibility,
|
|
74
|
+
core point visibility, and whether the point lands after the mobile clamp
|
|
66
75
|
- extracted hook patterns
|
|
67
76
|
- selected hook basis
|
|
68
77
|
|
|
@@ -83,6 +92,9 @@ Draft files must preserve:
|
|
|
83
92
|
- draft body
|
|
84
93
|
- validation receipt, including LinkedIn preview pass/warn/fail status and
|
|
85
94
|
compact fallback when the selected hook carries a warning
|
|
95
|
+
- rendered mobile and desktop preview blocks for the selected hook; drafts
|
|
96
|
+
cannot be ready when this rendered-preview audit is missing or fails mobile
|
|
97
|
+
visibility
|
|
86
98
|
- status: `draft`, `ready`, `needs_revision`, `published`, or `archived`
|
|
87
99
|
|
|
88
100
|
Multiple drafts for the same idea are expected. Keep the `ideaId` stable and
|
|
@@ -11,6 +11,7 @@ Every saved draft needs a validation receipt. A draft without this receipt is no
|
|
|
11
11
|
- `candidateHooksConsidered`
|
|
12
12
|
- `selectedHook`
|
|
13
13
|
- `selectedHookWhy`
|
|
14
|
+
- `sourceHookReachAudit`
|
|
14
15
|
- `proofClaimsUsed`
|
|
15
16
|
- `proofClaimSources`
|
|
16
17
|
- `storyFilesConsulted`
|
|
@@ -77,7 +78,17 @@ Each candidate should include:
|
|
|
77
78
|
- premise tension opened
|
|
78
79
|
- reader value implied
|
|
79
80
|
- source pattern
|
|
81
|
+
- source pattern reach signals: author follower count when available, target
|
|
82
|
+
follower band, follower-band fit, engagement per 1k followers, weighted
|
|
83
|
+
engagement per 1k followers, reach-adjusted score, baseline lift, and
|
|
84
|
+
confidence
|
|
80
85
|
- score
|
|
86
|
+
- `renderedPreview` using `references/linkedin-preview-rendering.md`
|
|
87
|
+
- literal mobile and desktop rendered preview blocks
|
|
88
|
+
- mobile and desktop rendered line wraps
|
|
89
|
+
- first-screen promise: pain, proof, or curiosity visible by the mobile clamp
|
|
90
|
+
- whether the core point is visible in the mobile rendered preview
|
|
91
|
+
- whether the point lands after the mobile clamp
|
|
81
92
|
- char count including newlines and first-line / first-two-line preview measurements
|
|
82
93
|
- physical line count, content line count, longest nonblank line, and blank-line risk
|
|
83
94
|
- `previewBudgetStatus`: `pass`, `warn`, or `fail`
|
|
@@ -98,7 +109,7 @@ After the first draft:
|
|
|
98
109
|
6. replace generic language with concrete words only when supported
|
|
99
110
|
7. preserve the user's actual story and point
|
|
100
111
|
8. remove AI tells
|
|
101
|
-
9. re-
|
|
112
|
+
9. re-render the selected hook on mobile and desktop after edits
|
|
102
113
|
|
|
103
114
|
## Premise Value Audit
|
|
104
115
|
|
|
@@ -147,24 +158,96 @@ If `selectedControversy` is missing, if the audience belief is only a generic
|
|
|
147
158
|
label like "founders want growth," or if `credibleWhyUs` depends on borrowed
|
|
148
159
|
proof from another creator, save as `needs_revision`.
|
|
149
160
|
|
|
150
|
-
##
|
|
161
|
+
## Source Hook Reach Audit
|
|
151
162
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
rendering varies by device, app version, font, media, and line break. This audit
|
|
155
|
-
is a mobile-first safety gate, not a claim about an official LinkedIn limit.
|
|
163
|
+
Before a draft can be `ready`, validate that the selected source hook pattern
|
|
164
|
+
was chosen for a reach-normalized reason, not raw audience size.
|
|
156
165
|
|
|
157
|
-
|
|
166
|
+
Record:
|
|
167
|
+
|
|
168
|
+
- `targetFollowerBand`
|
|
169
|
+
- `authorFollowerCount` for each source pattern when available
|
|
170
|
+
- `followerBandFit`: `in_target_band`, `below_target_band`,
|
|
171
|
+
`above_target_band`, or `unknown`
|
|
172
|
+
- `engagementPer1kFollowers`
|
|
173
|
+
- `weightedEngagementPer1kFollowers`
|
|
174
|
+
- `reachAdjustedScore`
|
|
175
|
+
- `reachPenaltyMultiplier`
|
|
176
|
+
- `creatorBaselineMedianEngagement` or `creator_baseline_unavailable`
|
|
177
|
+
- `baselineLift` or `creator_baseline_unavailable`
|
|
178
|
+
- `bigAccountPenaltyApplied`
|
|
179
|
+
- `whyTheHookCarries`
|
|
180
|
+
- `followerCountUnavailableSources`
|
|
181
|
+
- `whyThisHookIsAReachAdjustedSignal`
|
|
182
|
+
|
|
183
|
+
If the user asked for a follower range and the selected source pattern is from a
|
|
184
|
+
large account above the target range, the receipt must explain why it survived
|
|
185
|
+
the celebrity reach penalty. Use large-account hooks as secondary pattern
|
|
186
|
+
evidence unless they clearly overperform the creator's baseline or the hook
|
|
187
|
+
itself carries after reach is controlled. A draft cannot be `ready` when the
|
|
188
|
+
selected hook is justified only by raw total engagement or follower count.
|
|
189
|
+
|
|
190
|
+
## LinkedIn Preview Audit
|
|
158
191
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
192
|
+
Audit the selected hook and top candidates against
|
|
193
|
+
`references/linkedin-preview-rendering.md`. LinkedIn does not publish exact
|
|
194
|
+
"see more" cutoff rules, and rendering varies by device, app version, font,
|
|
195
|
+
media, and line break. This audit is a mobile-first rendered-preview safety
|
|
196
|
+
gate, not a claim about an official LinkedIn limit.
|
|
197
|
+
|
|
198
|
+
Character budgets are secondary diagnostics. They cannot be the only evidence
|
|
199
|
+
that a hook works. Every selected hook must include literal rendered mobile and
|
|
200
|
+
desktop preview blocks.
|
|
201
|
+
|
|
202
|
+
Default deterministic renderer when no authenticated LinkedIn screenshot is
|
|
203
|
+
available:
|
|
204
|
+
|
|
205
|
+
```text
|
|
206
|
+
cssContractVersion: linkedin-preview-rendering/v1
|
|
207
|
+
font size: 14px
|
|
208
|
+
line height: 21px
|
|
209
|
+
white space: pre-wrap
|
|
210
|
+
overflow wrap: break-word
|
|
211
|
+
mobile text width: 308px
|
|
212
|
+
desktop text width: 582px
|
|
213
|
+
review clamp: first 3 rendered text lines
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Use rendered gates:
|
|
217
|
+
|
|
218
|
+
- `pass`: the mobile rendered preview shows the pain, proof, or curiosity by
|
|
219
|
+
the end of the first 3 rendered lines, and the core point is understandable
|
|
220
|
+
without opening "see more".
|
|
221
|
+
- `warn`: the mobile rendered preview creates useful curiosity but the core
|
|
222
|
+
point is slightly softened by wrapping, blank-line rhythm, or one missing
|
|
223
|
+
context word. A compact fallback is required.
|
|
224
|
+
- `fail`: the hook's real point appears after the first 3 mobile rendered
|
|
225
|
+
lines, the first rendered line is generic setup, blank lines consume the
|
|
226
|
+
preview before the reader sees the point, or desktop fit is the only reason it
|
|
227
|
+
looks good.
|
|
162
228
|
|
|
163
229
|
Desktop preview usually has more room. Still record desktop fit, but never let
|
|
164
230
|
desktop fit compensate for a mobile `fail`.
|
|
165
231
|
|
|
166
232
|
Record:
|
|
167
233
|
|
|
234
|
+
- `renderedPreview`
|
|
235
|
+
- `renderBasis`: `linkedin_css_contract`, `authenticated_linkedin_screenshot`,
|
|
236
|
+
or `manual_user_source`
|
|
237
|
+
- `cssContractVersion`
|
|
238
|
+
- `mobileRenderedPreviewBlock`
|
|
239
|
+
- `desktopRenderedPreviewBlock`
|
|
240
|
+
- `mobileRenderedLines`
|
|
241
|
+
- `desktopRenderedLines`
|
|
242
|
+
- `mobileTextWidthPx`
|
|
243
|
+
- `desktopTextWidthPx`
|
|
244
|
+
- `mobileRenderedLineCount`
|
|
245
|
+
- `desktopRenderedLineCount`
|
|
246
|
+
- `corePainProofOrCuriosityVisibleMobile`
|
|
247
|
+
- `corePainProofOrCuriosityVisibleDesktop`
|
|
248
|
+
- `corePointVisibleMobile`
|
|
249
|
+
- `corePointVisibleDesktop`
|
|
250
|
+
- `pointAfterMobileClamp`
|
|
168
251
|
- `charCount`
|
|
169
252
|
- `charCountIncludingNewlines`
|
|
170
253
|
- `firstLineChars`
|
|
@@ -183,10 +266,14 @@ Record:
|
|
|
183
266
|
- `rewriteIfTruncated`
|
|
184
267
|
- `compactFallback` when `previewBudgetStatus` is `warn`
|
|
185
268
|
|
|
186
|
-
If the hook only works after
|
|
187
|
-
`ready` with `previewBudgetStatus: fail
|
|
188
|
-
`
|
|
189
|
-
|
|
269
|
+
If the hook only works after the rendered mobile clamp, rewrite it. A draft
|
|
270
|
+
cannot be `ready` with `previewBudgetStatus: fail`,
|
|
271
|
+
`mobilePreviewFit: fail`, missing `renderedPreview`,
|
|
272
|
+
`corePainProofOrCuriosityVisibleMobile: false`,
|
|
273
|
+
`corePointVisibleMobile: false`, or `pointAfterMobileClamp: true`. A draft may
|
|
274
|
+
be `ready` with `previewBudgetStatus: warn` only when the warning is explicit,
|
|
275
|
+
usually because the user prefers blank-line rhythm, and the receipt includes a
|
|
276
|
+
compact fallback.
|
|
190
277
|
|
|
191
278
|
## Simplifier / Concrete-Language Audit
|
|
192
279
|
|