@sellable/mcp 0.1.73 → 0.1.75
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/tools/bootstrap.d.ts +15 -1
- package/dist/tools/bootstrap.js +35 -1
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +33 -0
- package/skills/create-campaign-v2/SKILL.md +68 -25
- package/skills/create-campaign-v2/core/flow.v2.json +129 -3
- package/skills/generate-messages/SKILL.md +18 -5
- package/skills/research/config.json +0 -9
package/dist/index-dev.js
CHANGED
|
File without changes
|
package/dist/index.js
CHANGED
|
File without changes
|
|
@@ -19,6 +19,20 @@ type BootstrapBlockingError = {
|
|
|
19
19
|
message: string;
|
|
20
20
|
guidance: string;
|
|
21
21
|
};
|
|
22
|
+
type CampaignFramework = ReturnType<typeof getCampaignFramework>;
|
|
23
|
+
type BootstrapFrameworkSummary = {
|
|
24
|
+
flowVersion: CampaignFramework["flowVersion"];
|
|
25
|
+
policyChars: number;
|
|
26
|
+
flowWorkflow: string | null;
|
|
27
|
+
flowStepCount: number | null;
|
|
28
|
+
providerOrder: string[];
|
|
29
|
+
providerIds: string[];
|
|
30
|
+
pluginIds: string[];
|
|
31
|
+
overrideKeys: string[];
|
|
32
|
+
warningCount: number;
|
|
33
|
+
warnings: string[];
|
|
34
|
+
loadFullFrameworkWith: string;
|
|
35
|
+
};
|
|
22
36
|
type BootstrapCreateCampaignResult = {
|
|
23
37
|
requiredChecks: BootstrapCheck[];
|
|
24
38
|
blockingErrors: BootstrapBlockingError[];
|
|
@@ -28,7 +42,7 @@ type BootstrapCreateCampaignResult = {
|
|
|
28
42
|
flowVersion: "v1" | "v2";
|
|
29
43
|
campaignId: string | null;
|
|
30
44
|
auth: AuthStatus | null;
|
|
31
|
-
framework:
|
|
45
|
+
framework: BootstrapFrameworkSummary | null;
|
|
32
46
|
campaignContext: Awaited<ReturnType<typeof getCampaignContext>> | null;
|
|
33
47
|
subskillCatalog: ListSubskillPromptsResponse | null;
|
|
34
48
|
createCampaignSubskill: Omit<SubskillPromptResponse, "prompt"> | null;
|
package/dist/tools/bootstrap.js
CHANGED
|
@@ -34,6 +34,40 @@ function pushBlockingError(blockingErrors, check, message) {
|
|
|
34
34
|
guidance: toGuidance(check, message),
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
|
+
function summarizeFramework(framework) {
|
|
38
|
+
const flow = framework.flow;
|
|
39
|
+
const steps = Array.isArray(flow.steps) ? flow.steps : null;
|
|
40
|
+
const providerOrder = Array.isArray(framework.providerRegistry.defaultProviderOrder)
|
|
41
|
+
? framework.providerRegistry.defaultProviderOrder
|
|
42
|
+
: [];
|
|
43
|
+
const providerIds = Array.isArray(framework.providerRegistry.providers)
|
|
44
|
+
? framework.providerRegistry.providers
|
|
45
|
+
.map((provider) => provider.id)
|
|
46
|
+
.filter((id) => typeof id === "string")
|
|
47
|
+
: Object.keys(framework.providers || {});
|
|
48
|
+
const pluginIds = Array.isArray(framework.plugins)
|
|
49
|
+
? framework.plugins
|
|
50
|
+
.map((plugin) => plugin && typeof plugin === "object" && "id" in plugin
|
|
51
|
+
? plugin.id
|
|
52
|
+
: null)
|
|
53
|
+
.filter((id) => typeof id === "string")
|
|
54
|
+
: [];
|
|
55
|
+
return {
|
|
56
|
+
flowVersion: framework.flowVersion,
|
|
57
|
+
policyChars: framework.policy.length,
|
|
58
|
+
flowWorkflow: typeof flow.workflow === "string" ? flow.workflow : null,
|
|
59
|
+
flowStepCount: steps ? steps.length : null,
|
|
60
|
+
providerOrder,
|
|
61
|
+
providerIds,
|
|
62
|
+
pluginIds,
|
|
63
|
+
overrideKeys: Object.keys(framework.overrides || {}),
|
|
64
|
+
warningCount: framework.warnings.length,
|
|
65
|
+
warnings: framework.warnings,
|
|
66
|
+
loadFullFrameworkWith: framework.flowVersion === "v2"
|
|
67
|
+
? 'get_subskill_asset({ subskillName: "create-campaign-v2", assetPath: "core/flow.v2.json", offset?, limit? })'
|
|
68
|
+
: 'get_campaign_framework({ flowVersion: "v1", includePlugins: true })',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
37
71
|
export const bootstrapToolDefinitions = [
|
|
38
72
|
{
|
|
39
73
|
name: "bootstrap_create_campaign",
|
|
@@ -257,7 +291,7 @@ export async function bootstrapCreateCampaign(input = {}) {
|
|
|
257
291
|
flowVersion,
|
|
258
292
|
campaignId,
|
|
259
293
|
auth,
|
|
260
|
-
framework,
|
|
294
|
+
framework: framework ? summarizeFramework(framework) : null,
|
|
261
295
|
campaignContext,
|
|
262
296
|
subskillCatalog,
|
|
263
297
|
createCampaignSubskill: subskillMeta,
|
package/package.json
CHANGED
|
@@ -161,11 +161,44 @@ gates. Never use it to collect open text input like LinkedIn URLs, company
|
|
|
161
161
|
domains, notes, pasted context, campaign ideas, or feedback. For open text, ask
|
|
162
162
|
in normal chat and wait for the user to paste the value.
|
|
163
163
|
|
|
164
|
+
For campaign setup, every structured question is single-choice in both Claude
|
|
165
|
+
Code and Codex. Use mutually exclusive options, set or assume
|
|
166
|
+
`multiSelect: false`, and do not use checkbox or multi-select wording. If the
|
|
167
|
+
user needs a blended/custom answer, route them through `Other / custom` or a
|
|
168
|
+
free-text follow-up in normal chat.
|
|
169
|
+
|
|
164
170
|
Customer-facing language must call this "a couple setup choices" during normal
|
|
165
171
|
campaign progress. Use "quick question panel" only when explaining a missing
|
|
166
172
|
Codex/Claude setup capability. Do not tell customers about `request_user_input`,
|
|
167
173
|
Default mode, plugin caches, prompt loading, or skill file versions.
|
|
168
174
|
|
|
175
|
+
## Host Runtime Functions
|
|
176
|
+
|
|
177
|
+
Treat host capabilities as concrete functions, not prose conventions:
|
|
178
|
+
|
|
179
|
+
- `ask_user`: Claude Code uses `AskUserQuestion`; Codex uses
|
|
180
|
+
`request_user_input`. Use this for multiple-choice intake, campaign-focus
|
|
181
|
+
choices, source decisions, and approvals. Campaign setup questions are
|
|
182
|
+
single-choice only; do not use multi-select or checkbox variants. Never
|
|
183
|
+
render numbered plain-chat choices in an interactive session when the
|
|
184
|
+
structured question function is exposed.
|
|
185
|
+
- `load_subprompt`: call
|
|
186
|
+
`mcp__sellable__get_subskill_prompt({ subskillName, offset?, limit? })` and
|
|
187
|
+
continue chunks until `hasMore` is false.
|
|
188
|
+
- `load_subprompt_asset`: call
|
|
189
|
+
`mcp__sellable__get_subskill_asset({ subskillName, assetPath, offset?, limit? })`
|
|
190
|
+
and continue chunks until `hasMore` is false.
|
|
191
|
+
- `load_source_scout_registry`: call
|
|
192
|
+
`mcp__sellable__get_source_scout_registry({})` before any scout dispatch.
|
|
193
|
+
- `launch_source_scout`: Claude Code uses `Task` with `subagent_type` equal to
|
|
194
|
+
the registry `name`; Codex uses named custom agents such as
|
|
195
|
+
`source-scout-linkedin-engagement`, `source-scout-sales-nav`, and
|
|
196
|
+
`source-scout-prospeo-contact` when subagents are available.
|
|
197
|
+
|
|
198
|
+
If a required interactive host function is missing, stop and explain the
|
|
199
|
+
Sellable install/reload problem. Do not silently simulate structured choices,
|
|
200
|
+
subprompt loading, or source-scout dispatch with local scripts.
|
|
201
|
+
|
|
169
202
|
Never narrate local draft housekeeping to the user. If you create directories,
|
|
170
203
|
save drafts, write artifacts, or persist intermediate state, translate it into
|
|
171
204
|
the campaign benefit: consistent brief, approved lead source, reviewed message,
|
|
@@ -84,10 +84,15 @@ Validated draft directory:
|
|
|
84
84
|
`[features].default_mode_request_user_input = true`, not available in
|
|
85
85
|
`codex exec`). Treat them as equivalent approval/intake gates and persist the
|
|
86
86
|
same draft artifacts after the user answers. Use this structured gate only for
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
single-choice decisions with fixed options or approval gates. Every campaign
|
|
88
|
+
setup gate must be single-choice in both hosts: set or assume
|
|
89
|
+
`multiSelect: false`, use mutually exclusive option labels, and do not ask
|
|
90
|
+
for checkbox or multi-select answers. If a blended answer is useful, present
|
|
91
|
+
the blend as one explicit option or route the user through `Other / custom`
|
|
92
|
+
and a free-text follow-up in chat. Never use it to collect open text input
|
|
93
|
+
like LinkedIn URLs, company domains, notes, pasted context, campaign ideas,
|
|
94
|
+
or feedback. For open text, ask in normal chat and wait for the user to paste
|
|
95
|
+
the value. If an interactive
|
|
91
96
|
Codex session does not expose `request_user_input`, do not silently degrade to
|
|
92
97
|
a plain chat question; stop and tell the user:
|
|
93
98
|
|
|
@@ -234,12 +239,30 @@ Validated draft directory:
|
|
|
234
239
|
|
|
235
240
|
Sender options should include connected sender names if available, `same as
|
|
236
241
|
me`, `I’ll paste a different sender profile`, and `Other / custom`.
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
242
|
+
When the answer can be represented as choices, ask it with the host-native
|
|
243
|
+
structured question gate. Do not render sender or campaign-focus choices as a
|
|
244
|
+
numbered plain-chat list in interactive Claude Code or Codex. Plain chat is
|
|
245
|
+
only for free-text values like a pasted LinkedIn URL, company domain, CSV
|
|
246
|
+
path, or custom explanation.
|
|
247
|
+
|
|
248
|
+
After the user confirms the subject and sender, check whether the company
|
|
249
|
+
context implies more than one campaignable product line, service, or offer.
|
|
250
|
+
If so, ask one structured campaign-focus question before the setup packet
|
|
251
|
+
(for example, "Which Sellable offer is this campaign for?") with no more than
|
|
252
|
+
three specific options plus `Other / custom`. Do not ask this as plain
|
|
253
|
+
numbered chat.
|
|
254
|
+
|
|
255
|
+
Then run one lightweight sender/company research pass before asking buyer,
|
|
256
|
+
offer, proof, or source questions. Prefer loading
|
|
257
|
+
`get_subskill_prompt({ subskillName: "research-sender" })`, running its
|
|
258
|
+
fetch/profile/company/WebSearch batch when those tools are exposed, and
|
|
259
|
+
calling `complete_sender_research`. If WebSearch is unavailable, use the
|
|
260
|
+
available MCP profile/company/post tools, call `complete_sender_research`
|
|
261
|
+
with the evidence counts found, and continue with explicit gaps. The setup
|
|
262
|
+
questions should use the confirmed company context and researched proof /
|
|
263
|
+
positioning options so they do not feel generic. If identity is still
|
|
264
|
+
unavailable, use neutral/custom intake options instead of guessed
|
|
265
|
+
vertical-specific options.
|
|
243
266
|
|
|
244
267
|
- Before the identity gate, use this customer-facing shape:
|
|
245
268
|
|
|
@@ -272,9 +295,10 @@ me`, `I’ll paste a different sender profile`, and `Other / custom`.
|
|
|
272
295
|
draft-directory inspection/creation. `list_senders` is allowed once before the
|
|
273
296
|
first identity gate as a quiet token/sender inference shortcut, and once means
|
|
274
297
|
once: do not call it again after a LinkedIn lookup if it already ran. Do
|
|
275
|
-
draft-directory setup only after the founder answers. After launch identity
|
|
276
|
-
|
|
277
|
-
|
|
298
|
+
draft-directory setup only after the founder answers. After launch identity,
|
|
299
|
+
sender, and any ambiguous campaign focus are confirmed, the setup packet must
|
|
300
|
+
use the structured question gate and ask buyer, offer/CTA, proof, and lead
|
|
301
|
+
source. All four questions must include an `Other / custom` option.
|
|
278
302
|
- After the founder answers the first strategy/source packet, explain the next
|
|
279
303
|
stage only: campaign brief creation and brief approval. Use this shape:
|
|
280
304
|
|
|
@@ -432,11 +456,22 @@ should test for this campaign. Those can run in parallel and usually take
|
|
|
432
456
|
message quality gate outputs between `message-validation.md` and
|
|
433
457
|
`approval-packet.md`.
|
|
434
458
|
- Run the dependency chain as a DAG: `create-campaign-brief` -> `find leads`;
|
|
435
|
-
once `lead-review.md` and `lead-sample.json` exist,
|
|
436
|
-
`
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
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.
|
|
440
475
|
- `lead-sample.json` from `find leads` is always the message sample source.
|
|
441
476
|
`filter leads` must not create a different message sample or cause message
|
|
442
477
|
generation to fetch new prospects. The filter only marks which find-leads
|
|
@@ -452,10 +487,10 @@ should test for this campaign. Those can run in parallel and usually take
|
|
|
452
487
|
(display: LinkedIn Engagement Scout, powered by the `signal-discovery`
|
|
453
488
|
provider prompt), `source-scout-sales-nav` (Sales Nav Scout), and
|
|
454
489
|
`source-scout-prospeo-contact` (Prospeo Contact Scout). For Claude Code, explicitly
|
|
455
|
-
invoke the generated
|
|
456
|
-
for all credible lanes in one assistant message; they are
|
|
457
|
-
same canonical Sellable agent registry and carry explicit
|
|
458
|
-
allowlists. The parent thread should not preload every provider prompt before
|
|
490
|
+
invoke the generated `source-scout-*` Task/Agent subagents installed by
|
|
491
|
+
`@sellable/install` for all credible lanes in one assistant message; they are
|
|
492
|
+
installed from the same canonical Sellable agent registry and carry explicit
|
|
493
|
+
Sellable MCP tool allowlists. The parent thread should not preload every provider prompt before
|
|
459
494
|
spawning scouts; each scout loads only its own provider prompt. If host
|
|
460
495
|
subagents are unavailable, use independent MCP/tool calls
|
|
461
496
|
in the same model turn or dedicated Sellable MCP tools that perform
|
|
@@ -549,11 +584,19 @@ emphasis, tone, lead-source preference), always make it clear the user can give
|
|
|
549
584
|
a custom answer. Add an explicit `Other / custom` option to each subjective
|
|
550
585
|
question. Do not rely on prose like "you can add detail" as the only custom
|
|
551
586
|
path. Do not add custom options to the final six-choice commit gate.
|
|
587
|
+
Every subjective setup question is single-choice in both Claude Code and
|
|
588
|
+
Codex. Use mutually exclusive options, set or assume `multiSelect: false`, and
|
|
589
|
+
never use checkbox or multi-select wording that invites selecting several
|
|
590
|
+
options. If a blended answer is likely, make the blend a single named option or
|
|
591
|
+
route it through `Other / custom` and a normal-chat follow-up.
|
|
592
|
+
Do not batch setup as a Claude Code multi-select wizard; buyer, offer/CTA,
|
|
593
|
+
proof, and lead source remain single-choice questions even when the host
|
|
594
|
+
displays them in a sequence.
|
|
552
595
|
Use customer-facing question wording:
|
|
553
596
|
|
|
554
|
-
- target prospects: `Who should be the target prospects for this campaign
|
|
555
|
-
- main CTA / offer: `What should the main CTA or offer be
|
|
556
|
-
- proof emphasis: `Which proof point would most increase this buyer's confidence in {{company}}
|
|
597
|
+
- target prospects: `Who should be the target prospects for this campaign?`
|
|
598
|
+
- main CTA / offer: `What should the main CTA or offer be?`
|
|
599
|
+
- proof emphasis: `Which proof point would most increase this buyer's confidence in {{company}}?`
|
|
557
600
|
- lead source: `How should we get the people for this campaign?`
|
|
558
601
|
|
|
559
602
|
Ask the lead-source question as the last question in the first strategy
|
|
@@ -127,6 +127,35 @@
|
|
|
127
127
|
"mustNotInferFromNameOnly": true,
|
|
128
128
|
"fallback": "ask identity gate first; use neutral/custom intake options only when identity remains unavailable"
|
|
129
129
|
},
|
|
130
|
+
{
|
|
131
|
+
"action": "confirm_ambiguous_campaign_focus_with_structured_gate",
|
|
132
|
+
"when": "after_identity_before_founder_strategy_source_packet",
|
|
133
|
+
"allowedTools": ["AskUserQuestion", "request_user_input"],
|
|
134
|
+
"questionType": "single-choice only; plain chat only for free-text custom detail",
|
|
135
|
+
"multiSelect": false,
|
|
136
|
+
"maxOptions": 4,
|
|
137
|
+
"requiredOption": "Other / custom",
|
|
138
|
+
"chatRenderRule": "If the sender/company context has multiple campaignable product lines, services, or offers, ask exactly one single-choice structured campaign-focus question before buyer/offer/proof/source. Do not ask numbered plain-chat choices when the structured question tool is available. Do not use checkbox or multi-select wording."
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"action": "run_sender_company_research_before_strategy_packet",
|
|
142
|
+
"target": "research-sender",
|
|
143
|
+
"when": "after_identity_and_campaign_focus_before_founder_strategy_source_packet",
|
|
144
|
+
"allowedTools": [
|
|
145
|
+
"get_subskill_prompt",
|
|
146
|
+
"fetch_linkedin_profile",
|
|
147
|
+
"fetch_company",
|
|
148
|
+
"fetch_linkedin_posts",
|
|
149
|
+
"fetch_company_posts",
|
|
150
|
+
"WebFetch",
|
|
151
|
+
"WebSearch",
|
|
152
|
+
"ToolSearch",
|
|
153
|
+
"complete_sender_research"
|
|
154
|
+
],
|
|
155
|
+
"requiredCompletion": "complete_sender_research",
|
|
156
|
+
"fallback": "If WebSearch is unavailable, use available MCP profile/company/post tools, call complete_sender_research with observed counts, and carry explicit proof gaps into the setup packet.",
|
|
157
|
+
"chatRenderRule": "Use researched company positioning and proof options in the buyer/offer/proof/source setup packet; do not ask generic strategy questions from company name alone."
|
|
158
|
+
},
|
|
130
159
|
{
|
|
131
160
|
"action": "render_post_intake_progress_preamble",
|
|
132
161
|
"after": "founder_strategy_source_packet_answered",
|
|
@@ -194,6 +223,7 @@
|
|
|
194
223
|
],
|
|
195
224
|
"forbiddenOptionLabelReason": "Provider/source mechanics are internal to the 'Find people for me' path; first-time users should choose the job they need done, not the scouting provider.",
|
|
196
225
|
"customInput": true,
|
|
226
|
+
"multiSelect": false,
|
|
197
227
|
"lastQuestionInFirstStrategyBatch": true
|
|
198
228
|
}
|
|
199
229
|
],
|
|
@@ -518,10 +548,106 @@
|
|
|
518
548
|
"auto_continue"
|
|
519
549
|
],
|
|
520
550
|
"transitions": {
|
|
521
|
-
"lead_review_confirmed": "
|
|
551
|
+
"lead_review_confirmed": "post-lead-workstreams",
|
|
552
|
+
"revise_leads": "find-leads",
|
|
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",
|
|
522
647
|
"revise_leads": "find-leads",
|
|
523
|
-
"
|
|
524
|
-
"
|
|
648
|
+
"revise_rubric": "filter-rubric",
|
|
649
|
+
"revise_messaging": "message-generation",
|
|
650
|
+
"confirm_with_user": "message-review"
|
|
525
651
|
},
|
|
526
652
|
"interruptOnly": true
|
|
527
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,20 @@ 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
|
+
- do not mark `message-validation.md` as final or ready for message review until
|
|
96
|
+
`lead-filter.md` exists and the selected winner cites only rows that still
|
|
97
|
+
pass the filter
|
|
87
98
|
- generate 2-3 sample messages inline
|
|
88
99
|
- write findings to `message-validation.md`
|
|
89
100
|
- start `message-validation.md` with `Mode: DRY MODE (no DB mutation)`
|
|
@@ -98,9 +109,11 @@ Dry mode validates message quality before campaign mint.
|
|
|
98
109
|
Read:
|
|
99
110
|
|
|
100
111
|
- `brief.md`
|
|
101
|
-
- `lead-filter.md`
|
|
102
112
|
- `lead-sample.json` from the find-leads step; this is the only allowed sample
|
|
103
113
|
source for dry-mode message generation
|
|
114
|
+
- `lead-filter.md` when present. If it is absent because the caller launched
|
|
115
|
+
post-lead workstreams in parallel, start the prep/candidate stages and then
|
|
116
|
+
reconcile before final `message-validation.md`.
|
|
104
117
|
- `mcp/sellable/skills/create-campaign-brief/references/phase75-active-runtime-message-pack.md`
|
|
105
118
|
- `mcp/sellable/skills/create-campaign-v2/references/validation-criteria.md`
|
|
106
119
|
- `mcp/sellable/skills/create-campaign-v2/references/thomas-revision-filters.md`
|