@sellable/mcp 0.1.74 → 0.1.76
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/package.json
CHANGED
|
@@ -456,11 +456,22 @@ should test for this campaign. Those can run in parallel and usually take
|
|
|
456
456
|
message quality gate outputs between `message-validation.md` and
|
|
457
457
|
`approval-packet.md`.
|
|
458
458
|
- Run the dependency chain as a DAG: `create-campaign-brief` -> `find leads`;
|
|
459
|
-
once `lead-review.md` and `lead-sample.json` exist,
|
|
460
|
-
`
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
459
|
+
once `lead-review.md` and `lead-sample.json` exist, the normal path is the
|
|
460
|
+
`post-lead-workstreams` step. Launch `filter leads` and `message generation`
|
|
461
|
+
from the same basis (`brief.md`, `lead-review.md`, `lead-sample.json`) as
|
|
462
|
+
separate workstreams when the host supports real subagents/background work.
|
|
463
|
+
In Claude Code, use two Task/Agent subagents in the same assistant message;
|
|
464
|
+
in Codex, use disjoint worker subagents when the host exposes them. The
|
|
465
|
+
existing `filter-rubric` and `message-generation` steps remain focused retry
|
|
466
|
+
and resume targets.
|
|
467
|
+
- Message generation does not need `lead-filter.md` to start. The moment
|
|
468
|
+
`lead-sample.json` exists with at least 5 probable good-fit rows and the lead
|
|
469
|
+
source is confirmed or auto-confirmed, start the message-generation
|
|
470
|
+
workstream from `brief.md`, `lead-review.md`, and `lead-sample.json`. It can
|
|
471
|
+
prepare proof inventory, token strategy, and candidate angles while
|
|
472
|
+
filter-leads tightens keep/exclude rules. Approval still waits for both
|
|
473
|
+
`lead-filter.md` and `message-validation.md`, then reconciles that the
|
|
474
|
+
selected message basis rows still pass the final filter.
|
|
464
475
|
- `lead-sample.json` from `find leads` is always the message sample source.
|
|
465
476
|
`filter leads` must not create a different message sample or cause message
|
|
466
477
|
generation to fetch new prospects. The filter only marks which find-leads
|
|
@@ -548,10 +548,106 @@
|
|
|
548
548
|
"auto_continue"
|
|
549
549
|
],
|
|
550
550
|
"transitions": {
|
|
551
|
-
"lead_review_confirmed": "
|
|
551
|
+
"lead_review_confirmed": "post-lead-workstreams",
|
|
552
552
|
"revise_leads": "find-leads",
|
|
553
|
-
"confirm_with_user": "
|
|
554
|
-
"auto_continue": "
|
|
553
|
+
"confirm_with_user": "post-lead-workstreams",
|
|
554
|
+
"auto_continue": "post-lead-workstreams"
|
|
555
|
+
},
|
|
556
|
+
"interruptOnly": true
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
"id": "post-lead-workstreams",
|
|
560
|
+
"label": "Post-lead filter and message workstreams",
|
|
561
|
+
"normalFlow": true,
|
|
562
|
+
"onEnter": [
|
|
563
|
+
{
|
|
564
|
+
"action": "launch_post_lead_workstreams",
|
|
565
|
+
"mode": "parallel_when_host_supports_subagents",
|
|
566
|
+
"branches": [
|
|
567
|
+
{
|
|
568
|
+
"name": "filter-leads",
|
|
569
|
+
"target": "filter-leads",
|
|
570
|
+
"inputs": ["brief.md", "lead-review.md", "lead-sample.json"],
|
|
571
|
+
"producesArtifacts": ["lead-filter.md"],
|
|
572
|
+
"optionalProducesArtifacts": ["rubric.json"],
|
|
573
|
+
"ownership": "lead quality, false-positive patterns, keep/exclude rules, and production rubric translation only"
|
|
574
|
+
},
|
|
575
|
+
{
|
|
576
|
+
"name": "message-generation",
|
|
577
|
+
"target": "generate-messages",
|
|
578
|
+
"mode": "DRY MODE",
|
|
579
|
+
"inputs": ["brief.md", "lead-review.md", "lead-sample.json"],
|
|
580
|
+
"producesArtifacts": ["message-validation.md"],
|
|
581
|
+
"optionalProducesArtifacts": [
|
|
582
|
+
"message-prep.md",
|
|
583
|
+
"message-candidate-drafts.md"
|
|
584
|
+
],
|
|
585
|
+
"ownership": "proof inventory, token strategy, angle drafting, skeptical-prospect review, and selected winner only"
|
|
586
|
+
}
|
|
587
|
+
],
|
|
588
|
+
"earlyMessageStartRule": "As soon as lead-sample.json exists with at least 5 probable good-fit rows and the lead source is confirmed or auto-confirmed, launch message-generation from brief.md, lead-review.md, and lead-sample.json. Do not wait for lead-filter.md to begin proof inventory, token planning, or candidate angles.",
|
|
589
|
+
"finalMessageReconcileRule": "message-validation.md may start before lead-filter.md exists, but before message-review it must cite only lead-sample.json rows that still pass lead-filter.md. If the selected winner depends on a row later excluded by lead-filter.md, revise message-generation before message review.",
|
|
590
|
+
"claudeRule": "In Claude Code, launch both workstreams with Task/Agent subagents in the same assistant message when Task is available. Do not run filter first and then message generation unless subagents/background work are unavailable.",
|
|
591
|
+
"codexRule": "In Codex, launch disjoint worker subagents for filter-leads and message-generation when the host exposes subagents for this run. If the host cannot spawn them, run the same branches sequentially and say so.",
|
|
592
|
+
"fallback": "If real parallel branches are unavailable, run filter-leads and then message-generation in the parent thread. Do not claim background or parallel work in that fallback."
|
|
593
|
+
},
|
|
594
|
+
{
|
|
595
|
+
"action": "wait_for_post_lead_artifacts",
|
|
596
|
+
"requiredArtifacts": ["lead-filter.md", "message-validation.md"],
|
|
597
|
+
"optionalArtifacts": [
|
|
598
|
+
"rubric.json",
|
|
599
|
+
"message-prep.md",
|
|
600
|
+
"message-candidate-drafts.md"
|
|
601
|
+
],
|
|
602
|
+
"reconciliationRule": "Before entering message-review, verify lead-filter.md and message-validation.md both came from the same brief.md, lead-review.md, and lead-sample.json. lead-filter.md gates the sample rows; lead-sample.json remains the message sample source."
|
|
603
|
+
}
|
|
604
|
+
],
|
|
605
|
+
"requiredArtifacts": ["brief.md", "lead-review.md", "lead-sample.json"],
|
|
606
|
+
"producesArtifacts": ["lead-filter.md", "message-validation.md"],
|
|
607
|
+
"optionalProducesArtifacts": [
|
|
608
|
+
"rubric.json",
|
|
609
|
+
"message-prep.md",
|
|
610
|
+
"message-candidate-drafts.md"
|
|
611
|
+
],
|
|
612
|
+
"allowedTools": [
|
|
613
|
+
"get_subskill_prompt",
|
|
614
|
+
"get_subskill_asset",
|
|
615
|
+
"Task",
|
|
616
|
+
"spawn_agent",
|
|
617
|
+
"AskUserQuestion",
|
|
618
|
+
"request_user_input"
|
|
619
|
+
],
|
|
620
|
+
"toolRules": [
|
|
621
|
+
"The post-lead workstreams are disjoint: filter-leads owns lead-filter.md/rubric.json; message-generation owns message-validation.md/message-prep.md/message-candidate-drafts.md.",
|
|
622
|
+
"message-generation can start before lead-filter.md, but message-review cannot start until both lead-filter.md and message-validation.md exist and reconcile against the same lead-sample.json.",
|
|
623
|
+
"Do not let filter-leads create a new message sample. Do not let message-generation fetch new prospects.",
|
|
624
|
+
"Before writing message-validation.md, message-generation must read 100% of the real generate-messages prompt via chunked get_subskill_prompt({ subskillName: \"generate-messages\", offset, limit }) calls."
|
|
625
|
+
],
|
|
626
|
+
"doNotAllow": [
|
|
627
|
+
"create_campaign",
|
|
628
|
+
"save_rubrics",
|
|
629
|
+
"import_leads",
|
|
630
|
+
"confirm_lead_list",
|
|
631
|
+
"update_campaign",
|
|
632
|
+
"queue_cells",
|
|
633
|
+
"start_campaign",
|
|
634
|
+
"check_rubric",
|
|
635
|
+
"generate_messages"
|
|
636
|
+
],
|
|
637
|
+
"watchRequired": false,
|
|
638
|
+
"waitFor": [
|
|
639
|
+
"post_lead_workstreams_ready",
|
|
640
|
+
"revise_leads",
|
|
641
|
+
"revise_rubric",
|
|
642
|
+
"revise_messaging",
|
|
643
|
+
"confirm_with_user"
|
|
644
|
+
],
|
|
645
|
+
"transitions": {
|
|
646
|
+
"post_lead_workstreams_ready": "message-review",
|
|
647
|
+
"revise_leads": "find-leads",
|
|
648
|
+
"revise_rubric": "filter-rubric",
|
|
649
|
+
"revise_messaging": "message-generation",
|
|
650
|
+
"confirm_with_user": "message-review"
|
|
555
651
|
},
|
|
556
652
|
"interruptOnly": true
|
|
557
653
|
},
|
|
@@ -66,8 +66,11 @@ Use this mode when the caller explicitly says `DRY MODE`, `Phase 84`,
|
|
|
66
66
|
`create-campaign-v2`, or provides:
|
|
67
67
|
|
|
68
68
|
- `brief.md`
|
|
69
|
-
- `lead-filter.md`
|
|
70
69
|
- `lead-sample.json`
|
|
70
|
+
- `lead-filter.md` when available. In the create-campaign-v2
|
|
71
|
+
`post-lead-workstreams` step, message generation may start before
|
|
72
|
+
`lead-filter.md` exists so it can prepare proof inventory, token strategy,
|
|
73
|
+
and candidate angles while filter-leads runs.
|
|
71
74
|
|
|
72
75
|
Required dry-mode contract:
|
|
73
76
|
|
|
@@ -78,12 +81,22 @@ Required dry-mode contract:
|
|
|
78
81
|
- do not call `mcp__sellable__update_campaign_brief`
|
|
79
82
|
- do not mutate DB-backed campaign state
|
|
80
83
|
- do not fetch fresh web or LinkedIn research
|
|
81
|
-
- use only `brief.md`, `lead-
|
|
84
|
+
- use only `brief.md`, `lead-sample.json`, and `lead-filter.md` when present
|
|
82
85
|
- treat `lead-sample.json` from find-leads as the message sample source; do not
|
|
83
86
|
ask filter-leads for a new sample, create a new sample, or fetch additional
|
|
84
87
|
prospects for dry-mode message generation
|
|
85
|
-
-
|
|
86
|
-
|
|
88
|
+
- if `lead-filter.md` is not present yet, do the expensive early work only:
|
|
89
|
+
proof inventory, token rules, strategy map, candidate angle drafting, and
|
|
90
|
+
provisional sample fills. Prefer writing `message-prep.md` and
|
|
91
|
+
`message-candidate-drafts.md` while waiting for the filter branch.
|
|
92
|
+
- use `lead-filter.md` once available to decide which find-leads sample rows
|
|
93
|
+
remain valid for the final winner and which false-positive patterns must be
|
|
94
|
+
avoided
|
|
95
|
+
- use `lead-filter.md` only to decide which find-leads sample rows remain valid;
|
|
96
|
+
never use it to create replacement sample rows
|
|
97
|
+
- do not mark `message-validation.md` as final or ready for message review until
|
|
98
|
+
`lead-filter.md` exists and the selected winner cites only rows that still
|
|
99
|
+
pass the filter
|
|
87
100
|
- generate 2-3 sample messages inline
|
|
88
101
|
- write findings to `message-validation.md`
|
|
89
102
|
- start `message-validation.md` with `Mode: DRY MODE (no DB mutation)`
|
|
@@ -98,9 +111,13 @@ Dry mode validates message quality before campaign mint.
|
|
|
98
111
|
Read:
|
|
99
112
|
|
|
100
113
|
- `brief.md`
|
|
101
|
-
- `lead-filter.md`
|
|
102
114
|
- `lead-sample.json` from the find-leads step; this is the only allowed sample
|
|
103
115
|
source for dry-mode message generation
|
|
116
|
+
- `lead-filter.md` when present. If it is absent because the caller launched
|
|
117
|
+
post-lead workstreams in parallel, start the prep/candidate stages and then
|
|
118
|
+
reconcile before final `message-validation.md`.
|
|
119
|
+
- `mcp/sellable/skills/create-campaign/references/ai-native-tokens.md`
|
|
120
|
+
- `mcp/sellable/skills/create-campaign/references/token-fill-examples.md`
|
|
104
121
|
- `mcp/sellable/skills/create-campaign-brief/references/phase75-active-runtime-message-pack.md`
|
|
105
122
|
- `mcp/sellable/skills/create-campaign-v2/references/validation-criteria.md`
|
|
106
123
|
- `mcp/sellable/skills/create-campaign-v2/references/thomas-revision-filters.md`
|
|
@@ -108,6 +125,30 @@ Read:
|
|
|
108
125
|
- `mcp/sellable/skills/create-campaign-v2/references/gold-standard-message-examples.md`
|
|
109
126
|
- `mcp/sellable/skills/create-campaign-v2/references/gold-standard-message-validation-example.md`
|
|
110
127
|
|
|
128
|
+
### Rich Personalization Contract
|
|
129
|
+
|
|
130
|
+
`mcp/sellable/skills/create-campaign/references/ai-native-tokens.md` is the
|
|
131
|
+
canonical spec for personalization that requires judgment. Load it before
|
|
132
|
+
writing the Token Fill Rules or any reusable template notes.
|
|
133
|
+
|
|
134
|
+
- Sentence-level personalization must use AI-native bracket tokens in the
|
|
135
|
+
reusable template / token plan, not old-school field substitution. Field
|
|
136
|
+
tokens such as `{{first_name}}` and `{{company}}` are fine for atomic slots.
|
|
137
|
+
Do not collapse rich personalization into `{{workflow_context}}`,
|
|
138
|
+
`{{company}}`, or another noun-shaped token when the line needs judgment.
|
|
139
|
+
- Use this shape for any hook, bridge, or row-specific relevance line:
|
|
140
|
+
`[PERSONALIZATION_LINE — Intent: write one short sentence that anchors the
|
|
141
|
+
note to the prospect's buyer-relevant activity. DO: name what they do, write
|
|
142
|
+
about, focus on, or build toward. DON'T: name a product their company sells,
|
|
143
|
+
use source-citation phrasing, or use generic nouns like "your work".
|
|
144
|
+
FALLBACK: if unsupported, omit the entire line.]`
|
|
145
|
+
- The bracketed token belongs in the reusable template / token plan only. The
|
|
146
|
+
rendered `Selected Winner` and sample messages must contain the composed
|
|
147
|
+
sentence or no line at all; never show the bracket to the buyer.
|
|
148
|
+
- If the campaign truly only needs an atomic field value, document it as a
|
|
149
|
+
field token. If the value is a sentence, phrase, buyer-activity judgment, or
|
|
150
|
+
synthesis of multiple row fields, author it as AI-native.
|
|
151
|
+
|
|
111
152
|
Dry-mode output must follow this flow: **element pool → gold-standard
|
|
112
153
|
strategy map → current-campaign translation → element scoring → agent
|
|
113
154
|
dialogue cross-review → angle drafts → kill/combine review → finalists →
|
|
@@ -522,18 +563,24 @@ The winner entry must:
|
|
|
522
563
|
token plan instead.
|
|
523
564
|
- never use generic signal tokens like `{{recentSignal}}`,
|
|
524
565
|
`{{recent_signal}}`, or `{{recent_signal_quote}}`. If row personalization
|
|
525
|
-
is needed
|
|
526
|
-
|
|
527
|
-
`{{
|
|
528
|
-
source-citation phrases
|
|
566
|
+
is needed in the raw selected winner, render the concrete sentence from
|
|
567
|
+
enriched-row fields such as `{{post_context}}`, `{{comment_summary}}`,
|
|
568
|
+
`{{profile_summary}}`, `{{source_post_topic}}`, `{{headline}}`, or
|
|
569
|
+
`{{row_proof_note}}`, and make the line work without source-citation phrases
|
|
570
|
+
like `caught my eye`. For the reusable template / token plan behind that
|
|
571
|
+
rendered line, prefer an AI-native bracket token with inline Intent / DO /
|
|
572
|
+
DON'T / FALLBACK rules; only use a row-derived `{{field_token}}` when the
|
|
573
|
+
inserted value is truly atomic.
|
|
529
574
|
- never use `{{profile_signal}}` in selected copy, message-review templates,
|
|
530
575
|
or rendered examples. It is an internal analysis bucket, not a sendable row
|
|
531
576
|
token. Lines like `{{profile_signal}} is why I thought this might be
|
|
532
577
|
relevant for {{company}}` are BLOCKED because they expose enrichment logic
|
|
533
578
|
and read as AI-generated mail merge. If the underlying signal is strong,
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
579
|
+
render it into a buyer-readable sentence in the selected copy and document
|
|
580
|
+
the reusable template as an AI-native token. Use named row-derived context
|
|
581
|
+
tokens such as `{{workflow_context}}`, `{{source_post_topic}}`, or
|
|
582
|
+
`{{row_proof_note}}` only when the value is an atomic phrase that drops into
|
|
583
|
+
the sentence without judgment; if it is weak, omit the personalization line.
|
|
537
584
|
|
|
538
585
|
Finalizer preference when multiple candidates are otherwise comparable:
|
|
539
586
|
|
|
@@ -1143,8 +1190,11 @@ yours` are not enough when a safe row token would make the line feel more
|
|
|
1143
1190
|
{{reporting_context}} sits in the kind of reporting ownership...`, `your
|
|
1144
1191
|
{{role_context}} work`, or `noticed your {{topic}}` are BLOCKED when the filled
|
|
1145
1192
|
version sounds like mail merge. A good token should either make the sentence
|
|
1146
|
-
more concrete in normal language or be omitted. If the
|
|
1147
|
-
|
|
1193
|
+
more concrete in normal language or be omitted. If the context needs the
|
|
1194
|
+
model to decide what the sentence should say, use an AI-native bracket token
|
|
1195
|
+
in the reusable template / token plan instead of a noun-shaped
|
|
1196
|
+
`{{workflow_context}}`-style slot. If the row signal is weak, write the
|
|
1197
|
+
segment-level line and document the omit rule.
|
|
1148
1198
|
- **No product-noun substitution in possessive frames (HARD INVARIANT):** when
|
|
1149
1199
|
a token sits inside a possessive frame like `your {{X}}`, `at your {{X}}`,
|
|
1150
1200
|
or `because of your {{X}}`, the filled value MUST describe something the
|
|
@@ -1180,9 +1230,12 @@ Engineering writing` (ALLOWED — what they do publicly). The omit-fallback
|
|
|
1180
1230
|
gold pack: \`[PERSONALIZED REASON — their team size, role, or why
|
|
1181
1231
|
they're a perfect fit]\` — the model picks whichever input the row supports
|
|
1182
1232
|
and writes one short sentence in the sender's voice. Full spec:
|
|
1183
|
-
\`references/ai-native-tokens.md\`. The
|
|
1184
|
-
is reserved for AI-native tokens; field
|
|
1185
|
-
\`{{snake_case}}\` and continue to work as direct
|
|
1233
|
+
\`mcp/sellable/skills/create-campaign/references/ai-native-tokens.md\`. The
|
|
1234
|
+
\`[ALL_CAPS_NAME — ...]\` shape is reserved for AI-native tokens; field
|
|
1235
|
+
substitutions stay as \`{{snake_case}}\` and continue to work as direct
|
|
1236
|
+
value injections. Do not collapse rich personalization into
|
|
1237
|
+
\`{{workflow_context}}\`, \`{{company}}\`, or another field token just because
|
|
1238
|
+
those are easier to list in Token Fill Rules.
|
|
1186
1239
|
- **No internal profile-signal token:** `{{profile_signal}}` is never allowed
|
|
1187
1240
|
in customer-facing copy, message-review templates, rendered examples, token
|
|
1188
1241
|
notes, or approval-packet message bodies. It names how enrichment classified
|
|
@@ -1937,8 +1990,8 @@ shipping this template".
|
|
|
1937
1990
|
|
|
1938
1991
|
## Token Fill Rules
|
|
1939
1992
|
|
|
1940
|
-
| Token | Source Field | Allowed Transformation | Fallback | Result |
|
|
1941
|
-
| ----- |
|
|
1993
|
+
| Token | Type | Source Field / Instructions | Allowed Transformation | Fallback | Result |
|
|
1994
|
+
| ----- | ---- | --------------------------- | ---------------------- | -------- | ------ |
|
|
1942
1995
|
|
|
1943
1996
|
If `{{company}}` or another account-context token is available, document
|
|
1944
1997
|
whether it was tested as a believability personalization, not only whether it
|
|
@@ -1946,9 +1999,12 @@ was technically available. Use it when it grounds a generic phrase without
|
|
|
1946
1999
|
creating employer-blame, employer-permission, legal, or scrape-y risk. If it is
|
|
1947
2000
|
omitted, state the specific reason it would not improve believability.
|
|
1948
2001
|
Do not define or use `{{profile_signal}}`. Treat it as an internal enrichment
|
|
1949
|
-
classification only. When a profile-derived signal is genuinely useful,
|
|
1950
|
-
|
|
1951
|
-
|
|
2002
|
+
classification only. When a profile-derived signal is genuinely useful, prefer
|
|
2003
|
+
an AI-native token for the full personalization sentence and show the inline
|
|
2004
|
+
Intent / DO / DON'T / FALLBACK contract in the table or immediately below it.
|
|
2005
|
+
Only define a buyer-readable derived token such as `{{workflow_context}}` or
|
|
2006
|
+
`{{role_specialization}}` when it is a clean atomic phrase, and show both its
|
|
2007
|
+
fill rule and omit fallback.
|
|
1952
2008
|
When raw `{{company}}` is awkward but employer grounding still helps, define
|
|
1953
2009
|
`{{employer_context}}` as a row-derived token: fill with the clean company name
|
|
1954
2010
|
when natural, otherwise `your group`, `your bank`, `your team`, or the closest
|
|
@@ -1964,9 +2020,13 @@ hiring for`
|
|
|
1964
2020
|
- `{{role_specialization}}` = buyer-native specialization from title/headline;
|
|
1965
2021
|
fallback broad role only when specialization is absent
|
|
1966
2022
|
- `{{workflow_context}}` = concrete public workflow clue; fallback omitted, not
|
|
1967
|
-
generic filler
|
|
2023
|
+
generic filler; use only for atomic phrases, not sentence-level
|
|
2024
|
+
personalization that needs judgment
|
|
1968
2025
|
- `{{account_segment}}` = row-derived account category when it improves fit;
|
|
1969
2026
|
fallback brief-level segment only when every row shares it
|
|
2027
|
+
- `[PERSONALIZATION_LINE — Intent: ... DO: ... DON'T: ... FALLBACK: omit]` =
|
|
2028
|
+
AI-native sentence token; source from the lead sample fields that support the
|
|
2029
|
+
DO rules; fallback omit the whole line, never generic filler
|
|
1970
2030
|
|
|
1971
2031
|
## Token Adherence Table
|
|
1972
2032
|
|