@sellable/mcp 0.1.136 → 0.1.137

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.
@@ -1,7 +1,7 @@
1
1
  You are Lead Fit Builder for Sellable create-campaign-v2.
2
2
 
3
- Your job starts only after find-leads has produced `lead-review.md` and
4
- `lead-sample.json`, and the lead source has been approved or auto-confirmed.
3
+ Your job starts only after the lead source has been approved or auto-confirmed
4
+ and the bounded review batch exists in the campaign table.
5
5
  Work only on the lead filter branch. Do not source new leads, draft messages,
6
6
  import leads, create campaigns, or ask the user questions. Your only live
7
7
  campaign mutation is calling `save_rubrics` after the production rubrics are
@@ -9,41 +9,38 @@ ready.
9
9
 
10
10
  Required inputs:
11
11
 
12
- - `brief.md`
13
- - `lead-review.md`
14
- - `lead-sample.json`
15
- - campaign state from the parent thread
16
- - campaign table sample from the parent thread
12
+ - `campaignId`
13
+ - campaign revision or `campaignUpdatedAt`
14
+ - campaign brief content
15
+ - selected source decision and provider/list state
16
+ - `selectedLeadListId`
17
+ - `workflowTableId`
18
+ - imported review-batch rows, including row ids/hash when available
19
+ - filter choice
17
20
 
18
21
  Required first steps:
19
22
 
20
- 1. Read the three required inputs.
21
- 2. Load the filter-leads reference before writing artifacts:
23
+ 1. Verify the campaign/source/table ids from the parent thread match the live
24
+ campaign context.
25
+ 2. Load the filter-leads reference before designing rubrics:
22
26
  `get_subskill_asset({ subskillName: "create-campaign-v2", assetPath: "references/filter-leads.md" })`.
23
27
  3. Treat campaign state and the campaign table sample as the input of record.
24
- Disk files are context/debug aids, not durable state.
28
+ Do not require or hunt for local markdown/json artifacts.
25
29
 
26
30
  Owned outputs:
27
31
 
28
32
  - Durable campaign rubrics via `save_rubrics({ campaignOfferId, leadScoringRubrics })`
29
33
  when the filter is confirmed and production-shaped rubrics are safe to write.
30
34
  `save_rubrics` is the durable writer.
31
- - `lead-filter.md` debug artifact after the durable campaign write
32
- - `rubric.json` debug artifact after the durable campaign write
35
+ - concise filter/rubric summary returned to the parent thread
33
36
 
34
- Do not write or modify:
35
-
36
- - `message-validation.md`
37
- - `message-review.md`
38
- - `approval-packet.md`
39
- - `brief.md`
40
- - `lead-review.md`
41
- - `lead-sample.json`
37
+ Do not write or modify local markdown/json artifacts. Durable output is only
38
+ via `save_rubrics` plus the parent-thread summary.
42
39
 
43
40
  Process:
44
41
 
45
- 1. Preserve the approved source decision and the sample math from
46
- `lead-review.md`; do not re-run sourcing.
42
+ 1. Preserve the approved source decision and review-batch sample math supplied
43
+ by the parent; do not re-run sourcing.
47
44
  2. Turn the sample's good-fit and false-positive patterns into a strict but
48
45
  campaign-native filter.
49
46
  3. Include keep rules, exclude rules, sample false positives, pass-rate /
@@ -56,14 +53,11 @@ Process:
56
53
  6. If status is `confirmed`, call `save_rubrics` with 2-5 production-shaped
57
54
  active `leadScoringRubrics` before reporting success. If `save_rubrics`
58
55
  fails, stop and report the blocker; do not claim the filter is persisted.
59
- 7. Write `lead-filter.md` and `rubric.json` only as debug artifacts after
60
- campaign persistence succeeds.
61
56
 
62
57
  Return a concise final status with:
63
58
 
64
59
  - filter status: `confirmed`, `confirm-with-user`, or `revise-find-leads`
65
60
  - whether `save_rubrics` succeeded and how many active rubrics were persisted
66
- - artifacts written
67
61
  - strongest keep rules
68
62
  - strongest exclusion rules
69
63
  - expected pass-rate / yield impact
@@ -80,6 +80,27 @@ When reporting branch runtime proof, use this shape under
80
80
  Do not tell the UI to show Message Draft Builder as running unless this proof
81
81
  exists and points at the current non-empty bounded review batch.
82
82
 
83
+ ## Basis Changes And Rewrites
84
+
85
+ The first completed recommendation is the default message review candidate.
86
+ Do not automatically retry or regenerate only because Lead Fit Builder finished,
87
+ rubrics were saved, Filter Leads completed, enrichment cells populated, or more
88
+ row data became available after this branch started.
89
+
90
+ Treat later filter/enrichment data as optional rewrite context. If campaign id,
91
+ brief hash, selected source, `selectedLeadListId`, `workflowTableId`, and
92
+ review-batch row ids/hash still match, keep the initial recommendation usable
93
+ and report `status: ready` with `basisStatus: "usable_initial"` or
94
+ `"enriched_rewrite_available"`. The parent thread may offer the user a choice
95
+ to keep the initial draft or rewrite with enriched/filter data, but the rewrite
96
+ must be explicit user opt-in.
97
+
98
+ Retry or regenerate without asking only when the initial recommendation is
99
+ missing, failed, structurally invalid, unsafe, or mismatched on campaign id,
100
+ brief hash, selected source, `selectedLeadListId`, `workflowTableId`, or
101
+ review-batch rows. Filter/rubric/enrichment basis drift alone is not a stale
102
+ blocker.
103
+
83
104
  ## Hard Rules
84
105
 
85
106
  - Do not call product Generate Message cells. This worker drafts the template
@@ -158,22 +158,20 @@
158
158
  "displayName": "Lead Fit Builder",
159
159
  "target": "filter-leads",
160
160
  "inputs": [
161
- "brief.md",
162
- "lead-review.md",
163
- "lead-sample.json"
164
- ],
165
- "producesArtifacts": [
166
- "lead-filter.md"
167
- ],
168
- "optionalProducesArtifacts": [
169
- "rubric.json"
161
+ "campaignId",
162
+ "campaignBrief",
163
+ "source decision and selectedLeadList/source state",
164
+ "workflowTableId",
165
+ "imported review-batch rows"
170
166
  ],
167
+ "producesArtifacts": [],
168
+ "optionalProducesArtifacts": [],
171
169
  "ownership": "lead quality, false-positive patterns, keep/exclude rules, ability-to-pay checks, and production rubric translation only",
172
170
  "codex": {
173
171
  "description": "Lead Fit Builder for campaign-backed lead filtering and rubric persistence after source approval.",
174
172
  "model": "gpt-5.5",
175
173
  "modelReasoningEffort": "high",
176
- "sandboxMode": "workspace-write",
174
+ "sandboxMode": "read-only",
177
175
  "nicknameCandidates": [
178
176
  "Lead Fit Builder",
179
177
  "Fit Builder",
@@ -181,17 +179,12 @@
181
179
  ]
182
180
  },
183
181
  "claude": {
184
- "description": "Use proactively as Lead Fit Builder after lead source approval to persist campaign rubrics and write lead-filter debug artifacts from campaign state.",
182
+ "description": "Use proactively as Lead Fit Builder after lead source approval to persist campaign rubrics from campaign state.",
185
183
  "model": "inherit",
186
184
  "background": true,
187
185
  "maxTurns": 8,
188
186
  "color": "yellow",
189
187
  "tools": [
190
- "Read",
191
- "Write",
192
- "Edit",
193
- "Grep",
194
- "Glob",
195
188
  "mcp__sellable__get_subskill_prompt",
196
189
  "mcp__sellable__get_subskill_asset",
197
190
  "mcp__sellable__save_rubrics"
@@ -9,8 +9,8 @@ Required first step:
9
9
  "signal-discovery", campaignOfferId, confirmed: true })` and include that same
10
10
  `campaignOfferId` plus `currentStep: "signal-discovery"` in `search_signals`
11
11
  so the owning search route can show the source lane with current find-leads
12
- narration and user options. Treat that as a campaign-attached persisted
13
- search; do not run a post-mint search without the campaign ID. If no campaign
12
+ narration and user options. Treat that as a campaign-attached persisted search;
13
+ do not run a post-mint search without the campaign ID. If no campaign
14
14
  ID is supplied, run campaignless preview mode.
15
15
 
16
16
  Use the inherited Sellable MCP tools when available:
@@ -270,7 +270,7 @@ export async function bootstrapCreateCampaign(input = {}) {
270
270
  ? resumeDetected
271
271
  ? `Bootstrap complete.${workspaceNotice} Resume from campaign state and navigation diagnostics first; treat local draft artifacts as debug-only evidence. Then load ${createCampaignSubskill?.name ?? "create-campaign"} instructions with get_subskill_prompt({ subskillName: "${createCampaignSubskill?.name ?? "create-campaign"}" }); if the response has hasMore=true, continue with nextOffset until hasMore=false.`
272
272
  : flowVersion === "v2"
273
- ? `Bootstrap complete.${workspaceNotice} Load create-campaign-v2 instructions with get_subskill_prompt({ subskillName: "create-campaign-v2" }); if the response has hasMore=true, continue with nextOffset until hasMore=false. Preserve the pre-intake sequence: confirm auth/workspace status, identity setup, sender discovery/listing, and lightweight profile/company lookup. Then run the short setup/intake, write the campaign brief, call create_campaign once to mint the watchable shell, surface the returned watch link, and hand off to lead finding.`
273
+ ? `Bootstrap complete.${workspaceNotice} Load the compact create-campaign-v2 entry prompt once with get_subskill_prompt({ subskillName: "create-campaign-v2" }); load flow/reference assets lazily only when that stage needs them. Preserve the pre-intake sequence: confirm auth/workspace status, resolve campaign identity, and run lightweight profile/company lookup. Do not call list_senders or sender discovery during setup; sender availability belongs only to Settings after message approval. Then run the short setup/intake, write the campaign brief, call create_campaign once to mint the watchable shell, surface the returned watch link, and hand off to lead finding.`
274
274
  : `Bootstrap complete.${workspaceNotice} Load ${createCampaignSubskill?.name ?? "create-campaign"} instructions with get_subskill_prompt({ subskillName: "${createCampaignSubskill?.name ?? "create-campaign"}" }); if the response has hasMore=true, continue with nextOffset until hasMore=false. Follow that flow before calling create_campaign.`
275
275
  : "Bootstrap incomplete. Resolve blockingErrors and rerun bootstrap_create_campaign before provider/search/import tools.";
276
276
  // Strip prompt body from createCampaignSubskill — it's loaded via the host
@@ -243,6 +243,9 @@ function checkMessages(campaign) {
243
243
  if (!hasApprovedMessageTemplate(campaign)) {
244
244
  missing.push("approvedMessageTemplate");
245
245
  }
246
+ if (campaign.currentStep === "auto-execute-messaging") {
247
+ missing.push("generatedMessageReview");
248
+ }
246
249
  return { stepId: "messages", missing };
247
250
  }
248
251
  function checkSettings(campaign) {
@@ -99,9 +99,7 @@ export interface SourceScoutRegistryResponse {
99
99
  export interface PostFindLeadsScoutRegistryResponse {
100
100
  version: number;
101
101
  trigger: "find_leads_source_approved";
102
- requiredArtifacts?: string[];
103
102
  requiredInputs?: string[];
104
- optionalDebugArtifacts?: string[];
105
103
  scouts: Array<{
106
104
  id: string;
107
105
  name: string;
@@ -125,11 +123,9 @@ export interface PostFindLeadsScoutRegistryResponse {
125
123
  }>;
126
124
  joinGate: {
127
125
  afterAllComplete: boolean;
128
- requiredArtifacts?: string[];
129
126
  requiredState?: string[];
130
127
  noFilterRequiredState?: string[];
131
128
  skipFilterRule?: string;
132
- optionalDebugArtifacts?: string[];
133
129
  show: string[];
134
130
  nextStage: string;
135
131
  };
@@ -140,6 +136,7 @@ export interface PostFindLeadsScoutRegistryResponse {
140
136
  runtimeProofRequiredFields: string[];
141
137
  basisFields: string[];
142
138
  compactOutputFields: string[];
139
+ reusePolicy?: string;
143
140
  };
144
141
  usage: {
145
142
  codex: string;
@@ -263,7 +263,6 @@ export function getPostFindLeadsScoutRegistry() {
263
263
  "imported review-batch rows from selectedLeadList with row ids/hash",
264
264
  "filter choice and filter/rubric basis when present",
265
265
  ],
266
- optionalDebugArtifacts: ["brief.md", "lead-review.md", "lead-sample.json"],
267
266
  scouts: scouts.map((agent) => ({
268
267
  id: String(agent.id || ""),
269
268
  name: String(agent.name || ""),
@@ -294,7 +293,6 @@ export function getPostFindLeadsScoutRegistry() {
294
293
  requiredState: ["leadScoringRubrics", "messageDraftRecommendation"],
295
294
  noFilterRequiredState: ["messageDraftRecommendation"],
296
295
  skipFilterRule: "leadScoringRubrics may be absent only when the user explicitly skips filters with enableICPFilters=false; messageDraftRecommendation is still required before template review.",
297
- optionalDebugArtifacts: ["lead-filter.md", "message-validation.md"],
298
296
  show: ["readable_filters_with_reasons", "sample_message_for_approval"],
299
297
  nextStage: "message-review",
300
298
  },
@@ -332,16 +330,18 @@ export function getPostFindLeadsScoutRegistry() {
332
330
  "renderedSample",
333
331
  "concerns",
334
332
  "status",
333
+ "basisStatus",
335
334
  "basisToken",
336
335
  "outputAt",
337
336
  "outputHash",
338
337
  "error or retry detail",
339
338
  ],
339
+ reusePolicy: "The first completed Message Draft Builder recommendation remains the default review candidate. Later Lead Fit Builder, Filter Leads, enrichment, or rubric completion may make an enriched rewrite available, but does not automatically retry or replace the initial draft unless campaign/brief/source/list/table/review-batch identity mismatches or the initial output failed.",
340
340
  },
341
341
  usage: {
342
342
  codex: "After the user approves or auto-confirms the lead source, spawn both returned scout `name` values in one assistant turn only when the current Codex host exposes those custom agents.",
343
343
  claude: "After lead source approval, invoke both returned Task/Agent subagents in one assistant message only when the current Claude session lists those agents, so filter-leads and message generation run concurrently.",
344
- parentThreadRule: "Named agents are optional acceleration. If they are absent, do not customer-surface install status; the main thread still orchestrates filter and message branches from CampaignOffer state, selected source state, workflowTableId, and imported review-batch rows. Debug markdown/json artifacts are optional only. The message branch must load the full generate-messages prompt, must read live campaign/review-batch state through scoped MCP/product tools, must reject mismatched selectedLeadListId/workflowTableId/campaign/workspace input, and may use the create-campaign-v2 message-review safety gate as a supplemental approval check. Join before message review.",
344
+ parentThreadRule: "Named agents are optional acceleration. If they are absent, do not customer-surface install status; the main thread still orchestrates filter and message branches from CampaignOffer state, selected source state, workflowTableId, and imported review-batch rows. Local markdown/json files are not normal-path inputs. The message branch must load the full generate-messages prompt, must read live campaign/review-batch state through scoped MCP/product tools, must reject mismatched selectedLeadListId/workflowTableId/campaign/workspace input, and may use the create-campaign-v2 message-review safety gate as a supplemental approval check. Join before message review. Do not automatically rerun Message Draft Builder after filters/enrichment finish; show the initial draft by default and offer an enriched rewrite only with explicit user opt-in.",
345
345
  },
346
346
  };
347
347
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.136",
3
+ "version": "0.1.137",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",