@sellable/mcp 0.1.144 → 0.1.146
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/README.md +14 -3
- package/agents/post-find-leads-message-scout.md +8 -14
- package/agents/source-scout-linkedin-engagement.md +4 -3
- package/agents/source-scout-prospeo-contact.md +1 -1
- package/agents/source-scout-sales-nav.md +3 -2
- package/dist/server.js +29 -59
- package/dist/tools/auth.js +5 -5
- package/dist/tools/leads.js +70 -14
- package/dist/tools/registry.d.ts +4186 -0
- package/dist/tools/registry.js +59 -0
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +10 -9
- package/skills/create-campaign-v2/SKILL.md +12 -6
- package/skills/create-campaign-v2/SOUL.md +6 -2
- package/skills/create-campaign-v2/core/auto-execute.README.md +4 -4
- package/skills/create-campaign-v2/core/auto-execute.yaml +4 -4
- package/skills/create-campaign-v2/core/flow.v2.json +27 -5
- package/skills/create-campaign-v2/references/approval-gate-framing.md +1 -1
- package/skills/create-campaign-v2/references/filter-leads.md +42 -0
- package/skills/create-campaign-v2/references/message-review-safety-gate.md +22 -44
- package/skills/create-campaign-v2/references/sample-validation-loop.md +13 -13
- package/skills/create-campaign-v2/references/step-13-import-leads.md +14 -9
- package/skills/create-campaign-v2/references/watch-guide-narration.md +2 -2
- package/skills/load-voice/SKILL.md +129 -0
- package/skills/providers/prospeo.md +2 -1
- package/skills/providers/sales-nav.md +4 -2
- package/skills/providers/signal-discovery.md +12 -10
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { authToolDefinitions } from "./auth.js";
|
|
2
|
+
import { blueprintCommitToolDefinitions } from "./blueprint-commit.js";
|
|
3
|
+
import { bootstrapToolDefinitions } from "./bootstrap.js";
|
|
4
|
+
import { campaignToolDefinitions } from "./campaigns.js";
|
|
5
|
+
import { cellToolDefinitions } from "./cells.js";
|
|
6
|
+
import { startCliLoginToolDef, waitForCliLoginToolDef } from "./cli-login.js";
|
|
7
|
+
import { contextToolDefinitions } from "./context.js";
|
|
8
|
+
import { directCampaignToolDefinitions } from "./direct-campaigns.js";
|
|
9
|
+
import { engageBootstrapToolDefinitions } from "./engage-bootstrap.js";
|
|
10
|
+
import { engageDiscoveryToolDefinitions } from "./engage-discovery.js";
|
|
11
|
+
import { engageMemoryToolDefinitions } from "./engage-memory.js";
|
|
12
|
+
import { engageStateToolDefinitions } from "./engage-state.js";
|
|
13
|
+
import { enrichmentToolDefinitions } from "./enrichment.js";
|
|
14
|
+
import { frameworkToolDefinitions } from "./framework.js";
|
|
15
|
+
import { leadToolDefinitions } from "./leads.js";
|
|
16
|
+
import { linkedinToolDefinitions } from "./linkedin.js";
|
|
17
|
+
import { navigationToolDefinitions } from "./navigation.js";
|
|
18
|
+
import { onDemandToolDefinitions } from "./one-off.js";
|
|
19
|
+
import { processingToolDefinitions } from "./processing.js";
|
|
20
|
+
import { promptToolDefinitions } from "./prompts.js";
|
|
21
|
+
import { readinessToolDefinitions } from "./readiness.js";
|
|
22
|
+
import { rowToolDefinitions } from "./rows.js";
|
|
23
|
+
import { rubricToolDefinitions } from "./rubrics.js";
|
|
24
|
+
import { senderToolDefinitions } from "./senders.js";
|
|
25
|
+
import { sequencerToolDefinitions } from "./sequencer.js";
|
|
26
|
+
import { tableToolDefinitions } from "./tables.js";
|
|
27
|
+
import { verifyRowToolDefinitions } from "./verify-row.js";
|
|
28
|
+
import { workspaceToolDefinitions } from "./workspaces.js";
|
|
29
|
+
export const allTools = [
|
|
30
|
+
...campaignToolDefinitions,
|
|
31
|
+
...authToolDefinitions,
|
|
32
|
+
startCliLoginToolDef,
|
|
33
|
+
waitForCliLoginToolDef,
|
|
34
|
+
...bootstrapToolDefinitions,
|
|
35
|
+
...engageBootstrapToolDefinitions,
|
|
36
|
+
...engageDiscoveryToolDefinitions,
|
|
37
|
+
...workspaceToolDefinitions,
|
|
38
|
+
...frameworkToolDefinitions,
|
|
39
|
+
...contextToolDefinitions,
|
|
40
|
+
...navigationToolDefinitions,
|
|
41
|
+
...leadToolDefinitions,
|
|
42
|
+
...enrichmentToolDefinitions,
|
|
43
|
+
...processingToolDefinitions,
|
|
44
|
+
...rubricToolDefinitions,
|
|
45
|
+
...readinessToolDefinitions,
|
|
46
|
+
...rowToolDefinitions,
|
|
47
|
+
...cellToolDefinitions,
|
|
48
|
+
...promptToolDefinitions,
|
|
49
|
+
...linkedinToolDefinitions,
|
|
50
|
+
...onDemandToolDefinitions,
|
|
51
|
+
...directCampaignToolDefinitions,
|
|
52
|
+
...senderToolDefinitions,
|
|
53
|
+
...engageStateToolDefinitions,
|
|
54
|
+
...engageMemoryToolDefinitions,
|
|
55
|
+
...sequencerToolDefinitions,
|
|
56
|
+
...tableToolDefinitions,
|
|
57
|
+
...blueprintCommitToolDefinitions,
|
|
58
|
+
...verifyRowToolDefinitions,
|
|
59
|
+
];
|
package/package.json
CHANGED
|
@@ -152,13 +152,14 @@ For Signal Discovery, the customer-facing approval card must use the exact
|
|
|
152
152
|
action shape "Approve scraping N Signal Discovery posts?" and the chat summary
|
|
153
153
|
should be a compact `## Source Recommendation` block with:
|
|
154
154
|
|
|
155
|
-
-
|
|
156
|
-
-
|
|
157
|
-
-
|
|
155
|
+
- good-fit target: about 150 prospects after cleanup, enrichment, and filters
|
|
156
|
+
- source-candidate plan: about 1,000 raw engagers using a conservative 15%
|
|
157
|
+
fit-rate assumption unless sampled data supports a different number
|
|
158
|
+
- review checkpoint: import the first 25 leads for fit and message review
|
|
158
159
|
- a selected-post table with post author/topic, why it fits, and visible
|
|
159
160
|
engagement
|
|
160
161
|
- total visible pool and estimated good-fit pool
|
|
161
|
-
- first pass: build the source list, then import only
|
|
162
|
+
- first pass: build the source list, then import only the review
|
|
162
163
|
batch
|
|
163
164
|
- fallback: switch to Sales Nav recent activity if the review batch is
|
|
164
165
|
vendor-heavy, agency-heavy, or off-ICP
|
|
@@ -251,7 +252,7 @@ After every `update_campaign({ campaignId, currentStep })`, use
|
|
|
251
252
|
`get_campaign_navigation_state` when available as a compact orientation check:
|
|
252
253
|
match the saved campaign state to the expected watch-link step, explain the
|
|
253
254
|
current state in one sentence, and only then continue. Sender selection belongs
|
|
254
|
-
at Settings after message approval and
|
|
255
|
+
at Settings after message approval and review-batch validation. After message
|
|
255
256
|
validation, use Settings to help the user connect or select a LinkedIn sender.
|
|
256
257
|
Explain Slack reply review before launch. After sender selection, attach the
|
|
257
258
|
recommended sequence and move the watched UI to Send. Do not start the campaign
|
|
@@ -614,9 +615,9 @@ updates.
|
|
|
614
615
|
until `hasMore=false`. The create-campaign message-review safety gate is a
|
|
615
616
|
supplemental approval checklist, not a replacement for the long prompt. Use
|
|
616
617
|
campaign state, campaign brief content, selected source state, and imported
|
|
617
|
-
review-batch rows as the source of truth; do not read stale local markdown
|
|
618
|
-
inspect the database directly, or synthesize
|
|
619
|
-
general knowledge.
|
|
618
|
+
review-batch rows as the source of truth; do not read stale local markdown
|
|
619
|
+
such as `message-validation.md`, inspect the database directly, or synthesize
|
|
620
|
+
local validation artifacts from general knowledge.
|
|
620
621
|
5. Create the campaign shell early with the v1 brief so the user can open the
|
|
621
622
|
watch link and see useful setup state immediately. Import only the first
|
|
622
623
|
bounded review batch after the source is attached to the campaign; do not
|
|
@@ -640,7 +641,7 @@ updates.
|
|
|
640
641
|
`mcp__sellable__update_campaign({ campaignId, currentStep })` before major
|
|
641
642
|
visible work so the user can watch progress in the app: `create-offer` for
|
|
642
643
|
the brief, `pick-provider` or the selected provider step while sourcing,
|
|
643
|
-
`filter-choice` after the
|
|
644
|
+
`filter-choice` after the review batch, `create-icp-rubric` as soon
|
|
644
645
|
as filters are approved, `apply-icp-rubric` after rubrics save and while
|
|
645
646
|
waiting for message-template approval, `validate-sample` while the approved
|
|
646
647
|
template unlocks bounded enrichment/filter scoring on Filter Leads,
|
|
@@ -158,6 +158,12 @@ approval label must describe the action with the count, such as "Approve
|
|
|
158
158
|
scraping 3 Signal Discovery posts?" For Sales Nav or Prospeo, the label should
|
|
159
159
|
name the specific search/import lane. Do not call `import_leads` or
|
|
160
160
|
`confirm_lead_list` until this second source-action approval is granted.
|
|
161
|
+
After the user approves this concrete source-action gate, do not show the
|
|
162
|
+
Source Recommendation again and do not ask another source approval question.
|
|
163
|
+
Acknowledge once, then call `import_leads` immediately with the approved source
|
|
164
|
+
math. For Signal Discovery, pass `provider: "signal-discovery"`,
|
|
165
|
+
`targetEngagerCount`, `maxPostsToScrape`, and `confirmed: true`; the tool owns
|
|
166
|
+
moving the watch UI to source-list progress after a lead-list/job id exists.
|
|
161
167
|
|
|
162
168
|
For Signal Discovery, use this compact source-action approval shape after
|
|
163
169
|
selected posts exist:
|
|
@@ -167,9 +173,9 @@ selected posts exist:
|
|
|
167
173
|
|
|
168
174
|
Use Signal Discovery first.
|
|
169
175
|
|
|
170
|
-
**
|
|
171
|
-
**
|
|
172
|
-
**
|
|
176
|
+
**Good-fit target:** ~150 prospects after cleanup, enrichment, and filters<br>
|
|
177
|
+
**Source-candidate plan:** scrape ~1,000 raw engagers using a conservative 15% fit-rate assumption<br>
|
|
178
|
+
**Review checkpoint:** import the first 25 leads into the campaign for fit and message review before scaling<br>
|
|
173
179
|
|
|
174
180
|
### Selected posts
|
|
175
181
|
|
|
@@ -186,12 +192,12 @@ Use Signal Discovery first.
|
|
|
186
192
|
|
|
187
193
|
Approve scraping these 3 posts.
|
|
188
194
|
|
|
189
|
-
This gives enough volume to
|
|
195
|
+
This gives enough volume to work toward ~150 good-fit prospects, while
|
|
190
196
|
keeping the source tied to people already engaging with Claude Code outbound /
|
|
191
197
|
AI-native sales workflows.
|
|
192
198
|
|
|
193
|
-
**First pass:** build the source list, then import only
|
|
194
|
-
|
|
199
|
+
**First pass:** build the source list, then import only the 25-lead review
|
|
200
|
+
batch so we can inspect fit and messages before scaling.
|
|
195
201
|
|
|
196
202
|
**Fallback:** if the review batch is too vendor-heavy, agency-heavy, or
|
|
197
203
|
off-ICP, switch to Sales Nav recent activity.
|
|
@@ -238,11 +238,15 @@ for source approval before import.
|
|
|
238
238
|
|
|
239
239
|
For Signal Discovery, the second gate is not "approve source" in the abstract.
|
|
240
240
|
It is a concrete scrape approval: show a compact `## Source Recommendation`
|
|
241
|
-
with the ~
|
|
242
|
-
table, total visible pool, estimated good-fit pool, first-pass
|
|
241
|
+
with the ~150 good-fit prospect goal, 15% raw-engager assumption, selected-post
|
|
242
|
+
table, total visible pool, estimated good-fit pool, first-pass review
|
|
243
243
|
batch, and fallback. The approval question should be "Approve scraping N Signal
|
|
244
244
|
Discovery posts?"
|
|
245
245
|
|
|
246
|
+
That scrape approval is single-use. Once the user approves it, do not replay
|
|
247
|
+
the source card or ask for the same approval again. Acknowledge the approval in
|
|
248
|
+
one sentence and call `import_leads` for the approved source immediately.
|
|
249
|
+
|
|
246
250
|
## Parallelism + Naming
|
|
247
251
|
|
|
248
252
|
Source selection is sequential by default. Start with the first recommended
|
|
@@ -33,16 +33,16 @@ the imported review batch for validation).
|
|
|
33
33
|
|
|
34
34
|
- **`sampleSize`** — How many rows the validation loop pulls from the
|
|
35
35
|
imported review batch. In v2 this matches the review-batch cap
|
|
36
|
-
(default
|
|
36
|
+
(default 25), so the user sees enough real rows to judge the campaign
|
|
37
37
|
without spending credits on hundreds more.
|
|
38
38
|
- **`minProjectedPass`** — Passing-message floor required before handoff.
|
|
39
|
-
The default requires
|
|
39
|
+
The default requires 5 passing examples from the 25-row review batch.
|
|
40
40
|
Math:
|
|
41
41
|
```text
|
|
42
42
|
projectedPass = round(passInSample / sampleSize * importLimit)
|
|
43
43
|
```
|
|
44
|
-
With defaults (sampleSize=
|
|
45
|
-
the actual review-batch pass count.
|
|
44
|
+
With defaults (sampleSize=25, importLimit=25), `projectedPass` equals
|
|
45
|
+
the actual review-batch pass count. 5 passing rows is exactly at the
|
|
46
46
|
floor.
|
|
47
47
|
- **`maxRevisionRounds`** — Hard cap before escalating to the user. A
|
|
48
48
|
revision round is one full sample pass that triggered brief revision
|
|
@@ -17,7 +17,7 @@ import:
|
|
|
17
17
|
# Initial review batch imported in Step 13 before the sample validation
|
|
18
18
|
# loop. Import + enrichment must never exceed this cap before the user
|
|
19
19
|
# reviews the sample and explicitly asks to expand.
|
|
20
|
-
importLimit:
|
|
20
|
+
importLimit: 25
|
|
21
21
|
# Provider is inherited from the campaign-attached source association created
|
|
22
22
|
# during find-leads. Step 13 may re-run provider preflight in memory, but it
|
|
23
23
|
# does not choose a new source.
|
|
@@ -27,11 +27,11 @@ sample:
|
|
|
27
27
|
# Rows pulled from the imported cohort for the validation loop. In v2 this
|
|
28
28
|
# equals the review-batch cap so the user sees a focused first test batch
|
|
29
29
|
# without spending credits on hundreds of rows.
|
|
30
|
-
sampleSize:
|
|
30
|
+
sampleSize: 25
|
|
31
31
|
# Projected first-batch passing count required to proceed to sample
|
|
32
32
|
# messaging. This is not approval to scale the full source list.
|
|
33
33
|
# projectedPass = round(passInSample / sampleSize * importLimit).
|
|
34
|
-
minProjectedPass:
|
|
34
|
+
minProjectedPass: 5
|
|
35
35
|
# Hard cap on revision loops before escalating to the user. On a stale
|
|
36
36
|
# resume the counter does NOT reset — the 3-round cap holds across
|
|
37
37
|
# sessions.
|
|
@@ -106,7 +106,7 @@ handoff:
|
|
|
106
106
|
# Orientation surfaced in Step 16 ("awaiting-user-greenlight") along with
|
|
107
107
|
# the watch link. Keep this short and user-facing.
|
|
108
108
|
orientation: >-
|
|
109
|
-
Review the first
|
|
109
|
+
Review the first 25 enriched leads and messages. If they look good,
|
|
110
110
|
attach a sender in Settings, accept the recommended sequence, and start
|
|
111
111
|
the campaign without spending credits on more leads first.
|
|
112
112
|
|
|
@@ -460,7 +460,7 @@
|
|
|
460
460
|
"requiredInlineFields": [
|
|
461
461
|
"primary source and exact filters/recipe",
|
|
462
462
|
"specific source action awaiting approval",
|
|
463
|
-
"for Signal Discovery: Source Recommendation markdown with
|
|
463
|
+
"for Signal Discovery: Source Recommendation markdown with ~150 good-fit prospects as the target, source-candidate plan ~1,000 raw engagers at a conservative ~15% fit assumption, review checkpoint size, selected-post table, total visible pool, estimated good-fit pool, first pass, and fallback",
|
|
464
464
|
"for Signal Discovery: selected post count and target engager/source-candidate volume",
|
|
465
465
|
"bounded review batch size",
|
|
466
466
|
"runner-up and why it lost",
|
|
@@ -485,6 +485,16 @@
|
|
|
485
485
|
"signal-discovery": "Approve scraping {selectedPostCount} Signal Discovery posts?",
|
|
486
486
|
"sales-nav": "Import the approved Sales Nav review batch",
|
|
487
487
|
"prospeo": "Import the approved Prospeo review batch"
|
|
488
|
+
},
|
|
489
|
+
"postApprovalContract": {
|
|
490
|
+
"singleUseApproval": true,
|
|
491
|
+
"doNotRepeatAfterApproval": [
|
|
492
|
+
"Source Recommendation",
|
|
493
|
+
"show_source_decision_card",
|
|
494
|
+
"ask_source_review_choice"
|
|
495
|
+
],
|
|
496
|
+
"requiredNextActionAfterApproval": "acknowledge in one sentence, then call import_leads immediately",
|
|
497
|
+
"signalDiscoveryNextTool": "import_leads({ campaignOfferId, provider: \"signal-discovery\", targetEngagerCount, maxPostsToScrape, confirmed: true })"
|
|
488
498
|
}
|
|
489
499
|
}
|
|
490
500
|
],
|
|
@@ -541,7 +551,7 @@
|
|
|
541
551
|
"importLimit"
|
|
542
552
|
],
|
|
543
553
|
"requiredValues": {
|
|
544
|
-
"importLimit":
|
|
554
|
+
"importLimit": 25
|
|
545
555
|
},
|
|
546
556
|
"modeAddHandshake": {
|
|
547
557
|
"firstCallReturns": "needsModeSelection when adding to an existing campaign-attached list",
|
|
@@ -925,12 +935,24 @@
|
|
|
925
935
|
"messageDraftRecommendation"
|
|
926
936
|
],
|
|
927
937
|
"requiredVisibleLabels": [
|
|
928
|
-
"
|
|
929
|
-
"
|
|
938
|
+
"## Message Template",
|
|
939
|
+
"## Rendered Example",
|
|
940
|
+
"Good token fill:",
|
|
930
941
|
"My take:",
|
|
931
|
-
"Concern:",
|
|
932
942
|
"Question: approve-message or revise-messaging?",
|
|
933
943
|
"Recommendation:"
|
|
944
|
+
],
|
|
945
|
+
"doNotShowByDefault": [
|
|
946
|
+
"Token Notes",
|
|
947
|
+
"Good omit / fallback",
|
|
948
|
+
"Bad fill to avoid",
|
|
949
|
+
"Token Adherence Table"
|
|
950
|
+
],
|
|
951
|
+
"internalPersistenceOnly": [
|
|
952
|
+
"Token Fill Rules",
|
|
953
|
+
"Token Fill Examples",
|
|
954
|
+
"fallback guidance",
|
|
955
|
+
"bad-fill avoidance notes"
|
|
934
956
|
]
|
|
935
957
|
},
|
|
936
958
|
{
|
|
@@ -15,7 +15,7 @@ packet.
|
|
|
15
15
|
|
|
16
16
|
The approval gate used to be the place where the user authorized
|
|
17
17
|
spend/send-adjacent mutation. It is now compatibility-only. New runs import the
|
|
18
|
-
bounded
|
|
18
|
+
bounded review batch after source approval, save rubrics and the approved
|
|
19
19
|
message template after post-import review, and only then queue the cascade.
|
|
20
20
|
|
|
21
21
|
If `campaign-shell.json` exists, a draft `CampaignOffer` row already exists but
|
|
@@ -174,6 +174,14 @@ If more than roughly 20% of the review batch appears to be the forbidden side,
|
|
|
174
174
|
classify it as a list/source problem and return `revise-find-leads`; do not
|
|
175
175
|
hide that problem behind narrow rubrics.
|
|
176
176
|
|
|
177
|
+
## Suppression And Relationship Safety
|
|
178
|
+
|
|
179
|
+
Do not put DNC or one-off relationship-safety notes into production rubrics
|
|
180
|
+
unless the review batch shows that the pattern will leak at meaningful volume
|
|
181
|
+
and normal DNC/domain suppression will not catch it. Former employers, existing
|
|
182
|
+
customers, investors, partner lists, and one-off do-not-contact domains usually
|
|
183
|
+
belong in the recommendation as DNC/suppression instructions outside the rubric JSON.
|
|
184
|
+
|
|
177
185
|
## Production Rubric Shape
|
|
178
186
|
|
|
179
187
|
Confirmed rubrics must use the production `LeadScoringRubric` fields exactly:
|
|
@@ -265,6 +273,40 @@ Interpretation:
|
|
|
265
273
|
- Density dramatically below the band: likely source contamination, ICP drift,
|
|
266
274
|
or provider-side weakness; investigate before launch.
|
|
267
275
|
|
|
276
|
+
## Post-Filter Signal Enrichment Pass (Sales Nav lane)
|
|
277
|
+
|
|
278
|
+
Run this only for Sales Nav FIT rows when the downstream message step does not
|
|
279
|
+
already have row-level post evidence. In normal campaign-backed runs, use live
|
|
280
|
+
campaign-table row state as the source of truth. In explicit debug/UAT artifact
|
|
281
|
+
flows, append the diagnostic copy back to `lead-sample.json`.
|
|
282
|
+
|
|
283
|
+
This pass exists to protect the Earned-right and Read-as-1:1 substance filters.
|
|
284
|
+
Without row-level posts, message generation is likely to fall back to generic
|
|
285
|
+
category openers or presumed intent instead of evidence the recipient can
|
|
286
|
+
recognize.
|
|
287
|
+
|
|
288
|
+
Contract:
|
|
289
|
+
|
|
290
|
+
- scope: Sales Nav FIT rows only; do not enrich MAYBE or REJECT rows for this
|
|
291
|
+
pass
|
|
292
|
+
- budget cap: top 10 FIT rows by filter score
|
|
293
|
+
- tool: `mcp__sellable__fetch_linkedin_posts`, called per row
|
|
294
|
+
- fetch: most recent 3-5 public posts when available
|
|
295
|
+
- target surface: store each result as `recent_posts[]` entries with
|
|
296
|
+
`{ url, posted_at, excerpt }`; keep `recent_posts: []` for quiet profiles
|
|
297
|
+
- order of operations: run AFTER `lead-filter.md` is written, BEFORE
|
|
298
|
+
`message-validation.md` starts drafting
|
|
299
|
+
|
|
300
|
+
Record enrichment outcome in the filter summary: rows attempted, rows with
|
|
301
|
+
posts, rows with zero public posts, and tool failures. If more than half of the
|
|
302
|
+
attempted rows have zero posts, flag low signal density and tell message
|
|
303
|
+
generation to prefer trigger, peer-observation, or non-post proof instead of a
|
|
304
|
+
post-quote opener.
|
|
305
|
+
|
|
306
|
+
Do not convert "recently posted" or post availability into an ICP fit rubric.
|
|
307
|
+
The posts are message evidence only; buyer qualification still comes from role,
|
|
308
|
+
authority, account fit, capacity, geography, and exclusions.
|
|
309
|
+
|
|
268
310
|
## Decision Rules
|
|
269
311
|
|
|
270
312
|
- Use `confirmed` when the source lane is viable and the rubrics are enough to
|
|
@@ -31,8 +31,11 @@ instead of pulling the long prompt into the main thread.
|
|
|
31
31
|
local markdown/json artifacts in normal customer runs; emit debug artifacts
|
|
32
32
|
only when the parent explicitly asks for debug/UAT output.
|
|
33
33
|
5. Render the customer-facing message review in chat before asking for approval.
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
Keep chat lightweight: show the tokenized template and one strong rendered
|
|
35
|
+
good-fill example only. Do not print the token notes table, omit/fallback
|
|
36
|
+
example, or bad-fill analysis in chat unless the user explicitly asks.
|
|
37
|
+
After approval, the parent persists template, token rules, fallback guidance,
|
|
38
|
+
and bad-fill avoidance notes into campaign state with `update_campaign_brief`.
|
|
36
39
|
6. Ask exactly `approve-message` or `revise-messaging`. Do not import, queue,
|
|
37
40
|
attach sequence, or start before `approve-message`.
|
|
38
41
|
|
|
@@ -89,10 +92,17 @@ but the [topic] thread felt close enough to send`. Otherwise omit the
|
|
|
89
92
|
- If the message is plausible but not ready to send, set
|
|
90
93
|
`Recommendation: revise-messaging`.
|
|
91
94
|
|
|
95
|
+
## Internal Message Recommendation
|
|
96
|
+
|
|
97
|
+
The message scout or parent safety gate should still produce complete internal
|
|
98
|
+
review data: token-fill rules, one rendered omit/fallback example, and bad-fill
|
|
99
|
+
avoidance notes. This data is for campaign-brief persistence and safety checks,
|
|
100
|
+
not for the default chat approval packet.
|
|
101
|
+
|
|
92
102
|
## Customer-Facing Message Review
|
|
93
103
|
|
|
94
104
|
Render this in chat before asking. Use Markdown structure so the approval target
|
|
95
|
-
is visually scannable:
|
|
105
|
+
is visually scannable and low-overhead:
|
|
96
106
|
|
|
97
107
|
````markdown
|
|
98
108
|
Status: message-review
|
|
@@ -111,33 +121,11 @@ Status: message-review
|
|
|
111
121
|
{{tokenized_message_body}}
|
|
112
122
|
```
|
|
113
123
|
|
|
114
|
-
## Rendered
|
|
115
|
-
|
|
116
|
-
### Good token fill
|
|
117
|
-
|
|
118
|
-
Use when the row has a clean, supported fill.
|
|
119
|
-
|
|
120
|
-
```text
|
|
121
|
-
Subject: ...
|
|
122
|
-
|
|
123
|
-
Hey First,
|
|
124
|
-
|
|
125
|
-
...
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### Good omit / fallback
|
|
129
|
-
|
|
130
|
-
Use when a row signal or company context is missing, weak, or awkward.
|
|
131
|
-
|
|
132
|
-
```text
|
|
133
|
-
Subject: ...
|
|
134
|
-
|
|
135
|
-
Hey First,
|
|
124
|
+
## Rendered Example
|
|
136
125
|
|
|
137
|
-
|
|
138
|
-
```
|
|
126
|
+
### Example
|
|
139
127
|
|
|
140
|
-
|
|
128
|
+
Good token fill:
|
|
141
129
|
|
|
142
130
|
```text
|
|
143
131
|
Subject: ...
|
|
@@ -147,14 +135,6 @@ Hey First,
|
|
|
147
135
|
...
|
|
148
136
|
```
|
|
149
137
|
|
|
150
|
-
**Why this is wrong:** one sentence naming the exact token-fill failure.
|
|
151
|
-
|
|
152
|
-
## Token Notes
|
|
153
|
-
|
|
154
|
-
| Token | Use when | Fallback |
|
|
155
|
-
| ---------------- | ------------------------ | -------- |
|
|
156
|
-
| `{{first_name}}` | Clean first name exists. | `there` |
|
|
157
|
-
|
|
158
138
|
## Recommendation
|
|
159
139
|
|
|
160
140
|
**My take:** ...
|
|
@@ -168,15 +148,13 @@ Hey First,
|
|
|
168
148
|
|
|
169
149
|
Formatting requirements:
|
|
170
150
|
|
|
171
|
-
- Put the tokenized template and
|
|
151
|
+
- Put the tokenized template and rendered example in fenced `text` blocks
|
|
172
152
|
so chat gives them a distinct background.
|
|
173
|
-
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
none found`.
|
|
179
|
-
- Use a token notes table, not paragraph-only token notes.
|
|
153
|
+
- The chat example must contain a complete rendered subject + body, not a
|
|
154
|
+
bullet list of token names or a single bridge-line fragment.
|
|
155
|
+
- Do not show `Good omit / fallback`, `Bad fill to avoid`, or `Token Notes` in
|
|
156
|
+
the default chat approval packet. Keep those in the internal recommendation
|
|
157
|
+
and persist them to the campaign brief after approval.
|
|
180
158
|
- Keep reasoning outside the code blocks so the blocks are easy to inspect and
|
|
181
159
|
approve.
|
|
182
160
|
|
|
@@ -6,7 +6,7 @@ on every revision round.
|
|
|
6
6
|
|
|
7
7
|
## Principle
|
|
8
8
|
|
|
9
|
-
We spend a bounded review batch (default
|
|
9
|
+
We spend a bounded review batch (default 25 rows) to prove fit before the
|
|
10
10
|
user spends credits on hundreds more leads. The sample loop has one job:
|
|
11
11
|
answer the question "do we have enough real passing examples for the user to
|
|
12
12
|
judge this campaign?" Message generation starts earlier: the first row that
|
|
@@ -23,7 +23,7 @@ auto-revise leads.
|
|
|
23
23
|
- `CampaignOffer.currentStep === "apply-icp-rubric"` (the watched app is
|
|
24
24
|
already on Filter Leads after `save_rubrics`; `validate-sample` is the
|
|
25
25
|
logical loop name, not a visible route)
|
|
26
|
-
- Imported review batch from Step 13 (size: `importLimit`, default
|
|
26
|
+
- Imported review batch from Step 13 (size: `importLimit`, default 25)
|
|
27
27
|
- Config from `auto-execute.yaml`: `sample.sampleSize`,
|
|
28
28
|
`sample.minProjectedPass`, `sample.maxRevisionRounds`
|
|
29
29
|
- Persisted counter `revisionRound` (starts at 0 on first entry; persists
|
|
@@ -56,7 +56,7 @@ auto-revise leads.
|
|
|
56
56
|
6. wait_for_rubric_results(sample, targetCount = <cohortSize>, minPassedCount = 1)
|
|
57
57
|
- cohortSize = stats.totalRows of the enrichment batch, or the
|
|
58
58
|
imported batch count
|
|
59
|
-
- default targetCount=
|
|
59
|
+
- default targetCount=25 matches the default review batch, but pass the
|
|
60
60
|
explicit batch count anyway so future larger expansion batches do not
|
|
61
61
|
accidentally stop early
|
|
62
62
|
(see §Known Tool Behaviors #3)
|
|
@@ -172,8 +172,8 @@ company, enrichCellId, enrichStatus) over the default shape.
|
|
|
172
172
|
|
|
173
173
|
### 5. `wait_for_rubric_results` can timeout with enough signal to decide
|
|
174
174
|
|
|
175
|
-
Observed: a
|
|
176
|
-
and partial stats such as
|
|
175
|
+
Observed: a 25-row review batch may return `ready=false`, `reason="timeout"`,
|
|
176
|
+
and partial stats such as 20/25 scored, 4 passing, 4 messages generated. That is
|
|
177
177
|
enough to diagnose an underperforming sample. Waiting again without active
|
|
178
178
|
processing makes the experience feel frozen.
|
|
179
179
|
|
|
@@ -190,16 +190,16 @@ once only if active processing is still visible.
|
|
|
190
190
|
projectedPass = round(passInSample / sampleSize * importLimit)
|
|
191
191
|
```
|
|
192
192
|
|
|
193
|
-
Worked examples with defaults (sampleSize=
|
|
193
|
+
Worked examples with defaults (sampleSize=25, importLimit=25):
|
|
194
194
|
|
|
195
|
-
| passInSample | projectedPass | Handoff? (minProjectedPass=
|
|
195
|
+
| passInSample | projectedPass | Handoff? (minProjectedPass=5) |
|
|
196
196
|
| ------------ | ------------- | ----------------------------- |
|
|
197
197
|
| 0 | 0 | No — escalate or revise |
|
|
198
|
-
|
|
|
199
|
-
|
|
|
200
|
-
|
|
|
198
|
+
| 3 | 3 | No — escalate or revise |
|
|
199
|
+
| 5 | 5 | Yes — exactly at floor |
|
|
200
|
+
| 8 | 8 | Yes |
|
|
201
201
|
| 10 | 10 | Yes |
|
|
202
|
-
|
|
|
202
|
+
| 25 | 25 | Yes |
|
|
203
203
|
|
|
204
204
|
When non-default importLimit/sampleSize are configured, the math scales
|
|
205
205
|
the same way. In the default review-batch mode, the sample size equals the
|
|
@@ -263,8 +263,8 @@ rate is zero with no pattern that brief editing could fix.
|
|
|
263
263
|
|
|
264
264
|
Signal examples:
|
|
265
265
|
|
|
266
|
-
-
|
|
267
|
-
-
|
|
266
|
+
- 25/25 rows are wrong function / wrong seniority / wrong geo.
|
|
267
|
+
- 20/25 rows enrich to empty strings for the tokens the brief needs.
|
|
268
268
|
- Rubric passes 0 rows and the failure reasons are all "not ICP."
|
|
269
269
|
- **Marketplace supply-side contamination:** >20% of sample rows match
|
|
270
270
|
the brief §14 forbidden side (e.g. Skillsync sample contains
|
|
@@ -55,9 +55,9 @@ Supported branches:
|
|
|
55
55
|
`import_leads({ campaignOfferId })` for Signal Discovery unless selected posts
|
|
56
56
|
already exist on the campaign. Provider import materializes the source lead
|
|
57
57
|
list from the approved source-capacity plan; it is not the same target as the
|
|
58
|
-
|
|
58
|
+
default 25-row campaign review batch.
|
|
59
59
|
- **Supplied LinkedIn profile CSV** — confirm `load_csv_linkedin_leads` only
|
|
60
|
-
after
|
|
60
|
+
after the user approves that supplied-list source. Batch/materialize the
|
|
61
61
|
uploaded CSV into a Sellable lead-list table. Persist the returned
|
|
62
62
|
`leadListId`, then import the bounded review batch into the campaign table
|
|
63
63
|
with
|
|
@@ -106,9 +106,9 @@ fills the source lead list; it does **not** clone rows into the campaign table:
|
|
|
106
106
|
```text
|
|
107
107
|
import_leads({
|
|
108
108
|
campaignOfferId,
|
|
109
|
-
targetLeadCount: <
|
|
109
|
+
targetLeadCount: <sourceCandidateTarget; provider default>,
|
|
110
110
|
// Signal Discovery only:
|
|
111
|
-
targetEngagerCount: <ceil(
|
|
111
|
+
targetEngagerCount: <ceil(targetGoodFitLeads / sampledFitRateAfterCleanup)>,
|
|
112
112
|
maxPostsToScrape: <postsNeeded from approved math>
|
|
113
113
|
})
|
|
114
114
|
```
|
|
@@ -120,9 +120,12 @@ so dedup ratios are visible.
|
|
|
120
120
|
|
|
121
121
|
For Signal Discovery, do not scrape every currently selected/promoted sample
|
|
122
122
|
post by default. Before `import_leads`, reconcile selected posts with the
|
|
123
|
-
approved source math.
|
|
124
|
-
|
|
125
|
-
|
|
123
|
+
approved source math. The default good-fit target is 150 and the conservative
|
|
124
|
+
fallback fit rate is 15%, so the default source-candidate plan is about 1,000
|
|
125
|
+
raw engagers. If the sampled fit rate is stronger or weaker, use the sampled
|
|
126
|
+
rate with a conservative cleanup factor, cap the source candidates at the
|
|
127
|
+
approved provider limit, and select only enough posts to reach that engager
|
|
128
|
+
count. The subsequent
|
|
126
129
|
`confirm_lead_list` call still uses `targetLeadCount: <importLimit>` so only the
|
|
127
130
|
bounded review batch enters the campaign table.
|
|
128
131
|
|
|
@@ -216,8 +219,10 @@ cannot scale further without a new source lane.
|
|
|
216
219
|
- Zero-imported + zero-skipped ⇒ hard-fail escalate.
|
|
217
220
|
- Zero-imported + high-skipped ⇒ lane-exhausted operator notice (NOT a
|
|
218
221
|
silent proceed).
|
|
219
|
-
- `import_leads` is
|
|
220
|
-
|
|
222
|
+
- `import_leads` is allowed immediately after the concrete source-action
|
|
223
|
+
approval. It materializes the source list and then `confirm_lead_list` imports
|
|
224
|
+
only the bounded review batch. Enrichment, fit scoring, and message cells wait
|
|
225
|
+
for saved rubrics plus the approved message set.
|
|
221
226
|
- Step 13 MUST reuse an approved source already attached with `campaignOfferId`
|
|
222
227
|
before `import_leads`; it does not replay provider searches.
|
|
223
228
|
- `import_leads` is NOT called again in Step 14 (validate-sample). Full
|
|
@@ -178,8 +178,8 @@ Source approved and import starting:
|
|
|
178
178
|
{
|
|
179
179
|
"stage": "review-batch",
|
|
180
180
|
"headline": "Importing the review batch",
|
|
181
|
-
"visibleState": "The browser is still showing the approved LinkedIn Engagement source
|
|
182
|
-
"agentIntent": "Codex is importing only the bounded
|
|
181
|
+
"visibleState": "The browser is still showing the approved LinkedIn Engagement source candidates.",
|
|
182
|
+
"agentIntent": "Codex is importing only the bounded review batch into the campaign now.",
|
|
183
183
|
"nextAction": "Review batch ready"
|
|
184
184
|
}
|
|
185
185
|
```
|