@sellable/mcp 0.1.143 → 0.1.145
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 +19 -6
- package/agents/post-find-leads-message-scout.md +44 -0
- package/agents/registry.json +2 -2
- 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/index-dev.js +0 -0
- package/dist/index.js +0 -0
- package/dist/tools/leads.js +168 -14
- package/dist/tools/processing.d.ts +1 -0
- package/dist/tools/prompts.js +3 -3
- package/dist/tools/rubrics.js +14 -9
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +55 -34
- package/skills/create-campaign-v2/SKILL.md +59 -9
- package/skills/create-campaign-v2/SOUL.md +20 -12
- 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 +55 -19
- 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/final-handoff-contract.md +5 -5
- package/skills/create-campaign-v2/references/message-review-safety-gate.md +88 -13
- package/skills/create-campaign-v2/references/sample-validation-loop.md +18 -15
- package/skills/create-campaign-v2/references/step-13-import-leads.md +9 -6
- package/skills/create-campaign-v2/references/step-15-re-cascade.md +2 -3
- package/skills/create-campaign-v2/references/watch-guide-narration.md +39 -24
- package/skills/create-campaign-v2/references/watch-link-handoff.md +1 -1
- package/skills/create-campaign-v2-tail/SKILL.md +26 -13
- 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
- package/skills/research/config.json +9 -0
|
@@ -33,8 +33,8 @@ order (all before waiting for the user):
|
|
|
33
33
|
`get_campaign_navigation_state` when available so the watch link visibly
|
|
34
34
|
lands on Settings before sender setup.
|
|
35
35
|
4. Explain sender setup and Slack in normal customer language: Sellable needs a
|
|
36
|
-
connected LinkedIn sender
|
|
37
|
-
|
|
36
|
+
connected LinkedIn sender for launch, and Slack reply review matters because
|
|
37
|
+
replies and approvals need a channel the team will monitor.
|
|
38
38
|
5. If no connected sender exists, surface the campaign Settings link
|
|
39
39
|
`/campaign-builder/{campaignId}/settings?mode=claude`, tell the user to
|
|
40
40
|
connect a sender there, and STOP. Do not attach sequence and do not start.
|
|
@@ -70,7 +70,7 @@ The final handoff must answer five customer questions in plain language:
|
|
|
70
70
|
- why the selected LinkedIn sender and Slack reply review matter before launch
|
|
71
71
|
- what clicking Start does (approves/starts the campaign send path)
|
|
72
72
|
- how to revise (reply with what to change, or use the campaign UI)
|
|
73
|
-
-
|
|
73
|
+
- current launch status and what the final Start action does
|
|
74
74
|
|
|
75
75
|
When `lead-source-intake.json` exists, also answer:
|
|
76
76
|
|
|
@@ -84,8 +84,8 @@ When `lead-source-intake.json` exists, also answer:
|
|
|
84
84
|
|
|
85
85
|
Use the exact state name `awaiting-user-greenlight` so logs and UX artifacts
|
|
86
86
|
can verify the state-machine stop point, but explain it in normal words: the
|
|
87
|
-
campaign is built, sender/sequence setup is being completed, and
|
|
88
|
-
|
|
87
|
+
campaign is built, sender/sequence setup is being completed, and the final
|
|
88
|
+
start decision is still ahead. The watched UI may advance through
|
|
89
89
|
Settings, Sequence, and Send while this state-machine step remains the final
|
|
90
90
|
handoff.
|
|
91
91
|
|
|
@@ -91,19 +91,94 @@ but the [topic] thread felt close enough to send`. Otherwise omit the
|
|
|
91
91
|
|
|
92
92
|
## Customer-Facing Message Review
|
|
93
93
|
|
|
94
|
-
Render this in chat before asking
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
94
|
+
Render this in chat before asking. Use Markdown structure so the approval target
|
|
95
|
+
is visually scannable:
|
|
96
|
+
|
|
97
|
+
````markdown
|
|
98
|
+
Status: message-review
|
|
99
|
+
|
|
100
|
+
## Message Template
|
|
101
|
+
|
|
102
|
+
**Subject**
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
{{tokenized_subject}}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Body**
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
{{tokenized_message_body}}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Rendered Examples
|
|
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,
|
|
136
|
+
|
|
137
|
+
...
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Bad fill to avoid
|
|
141
|
+
|
|
142
|
+
```text
|
|
143
|
+
Subject: ...
|
|
144
|
+
|
|
145
|
+
Hey First,
|
|
146
|
+
|
|
147
|
+
...
|
|
148
|
+
```
|
|
149
|
+
|
|
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
|
+
## Recommendation
|
|
159
|
+
|
|
160
|
+
**My take:** ...
|
|
161
|
+
|
|
162
|
+
**Suggested adjustment:** ...
|
|
163
|
+
|
|
164
|
+
**Question:** approve-message or revise-messaging?
|
|
165
|
+
|
|
166
|
+
**Recommendation:** approve-message
|
|
167
|
+
````
|
|
168
|
+
|
|
169
|
+
Formatting requirements:
|
|
170
|
+
|
|
171
|
+
- Put the tokenized template and every rendered example in fenced `text` blocks
|
|
172
|
+
so chat gives them a distinct background.
|
|
173
|
+
- `Good token fill` and `Good omit / fallback` must each contain a complete
|
|
174
|
+
rendered subject + body, not a bullet list of token names or a single
|
|
175
|
+
bridge-line fragment.
|
|
176
|
+
- Include `Bad fill to avoid` when the row sample has a tempting but unsafe
|
|
177
|
+
source-mechanics or raw-headline fill; otherwise include `Bad fill to avoid:
|
|
178
|
+
none found`.
|
|
179
|
+
- Use a token notes table, not paragraph-only token notes.
|
|
180
|
+
- Keep reasoning outside the code blocks so the blocks are easy to inspect and
|
|
181
|
+
approve.
|
|
107
182
|
|
|
108
183
|
`My take` and `Suggested adjustment` must be specific. The adjustment can be
|
|
109
184
|
"approve as-is, or revise once to X if you want Y"; it must not be empty.
|
|
@@ -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
|
|
@@ -20,8 +20,10 @@ auto-revise leads.
|
|
|
20
20
|
|
|
21
21
|
## Inputs
|
|
22
22
|
|
|
23
|
-
- `CampaignOffer.currentStep === "
|
|
24
|
-
|
|
23
|
+
- `CampaignOffer.currentStep === "apply-icp-rubric"` (the watched app is
|
|
24
|
+
already on Filter Leads after `save_rubrics`; `validate-sample` is the
|
|
25
|
+
logical loop name, not a visible route)
|
|
26
|
+
- Imported review batch from Step 13 (size: `importLimit`, default 25)
|
|
25
27
|
- Config from `auto-execute.yaml`: `sample.sampleSize`,
|
|
26
28
|
`sample.minProjectedPass`, `sample.maxRevisionRounds`
|
|
27
29
|
- Persisted counter `revisionRound` (starts at 0 on first entry; persists
|
|
@@ -48,12 +50,13 @@ auto-revise leads.
|
|
|
48
50
|
the enrichment batch ids; NOT by calling wait_for_rubric_results
|
|
49
51
|
before rubric was scheduled)
|
|
50
52
|
|
|
51
|
-
5. check_rubric
|
|
53
|
+
5. do not call `check_rubric`; the product cascade runs enrichment and rubric
|
|
54
|
+
scoring from the queued Enrich Prospect cells
|
|
52
55
|
|
|
53
56
|
6. wait_for_rubric_results(sample, targetCount = <cohortSize>, minPassedCount = 1)
|
|
54
57
|
- cohortSize = stats.totalRows of the enrichment batch, or the
|
|
55
58
|
imported batch count
|
|
56
|
-
- default targetCount=
|
|
59
|
+
- default targetCount=25 matches the default review batch, but pass the
|
|
57
60
|
explicit batch count anyway so future larger expansion batches do not
|
|
58
61
|
accidentally stop early
|
|
59
62
|
(see §Known Tool Behaviors #3)
|
|
@@ -169,8 +172,8 @@ company, enrichCellId, enrichStatus) over the default shape.
|
|
|
169
172
|
|
|
170
173
|
### 5. `wait_for_rubric_results` can timeout with enough signal to decide
|
|
171
174
|
|
|
172
|
-
Observed: a
|
|
173
|
-
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
|
|
174
177
|
enough to diagnose an underperforming sample. Waiting again without active
|
|
175
178
|
processing makes the experience feel frozen.
|
|
176
179
|
|
|
@@ -187,16 +190,16 @@ once only if active processing is still visible.
|
|
|
187
190
|
projectedPass = round(passInSample / sampleSize * importLimit)
|
|
188
191
|
```
|
|
189
192
|
|
|
190
|
-
Worked examples with defaults (sampleSize=
|
|
193
|
+
Worked examples with defaults (sampleSize=25, importLimit=25):
|
|
191
194
|
|
|
192
|
-
| passInSample | projectedPass | Handoff? (minProjectedPass=
|
|
195
|
+
| passInSample | projectedPass | Handoff? (minProjectedPass=5) |
|
|
193
196
|
| ------------ | ------------- | ----------------------------- |
|
|
194
197
|
| 0 | 0 | No — escalate or revise |
|
|
195
|
-
|
|
|
196
|
-
|
|
|
197
|
-
|
|
|
198
|
+
| 3 | 3 | No — escalate or revise |
|
|
199
|
+
| 5 | 5 | Yes — exactly at floor |
|
|
200
|
+
| 8 | 8 | Yes |
|
|
198
201
|
| 10 | 10 | Yes |
|
|
199
|
-
|
|
|
202
|
+
| 25 | 25 | Yes |
|
|
200
203
|
|
|
201
204
|
When non-default importLimit/sampleSize are configured, the math scales
|
|
202
205
|
the same way. In the default review-batch mode, the sample size equals the
|
|
@@ -260,8 +263,8 @@ rate is zero with no pattern that brief editing could fix.
|
|
|
260
263
|
|
|
261
264
|
Signal examples:
|
|
262
265
|
|
|
263
|
-
-
|
|
264
|
-
-
|
|
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.
|
|
265
268
|
- Rubric passes 0 rows and the failure reasons are all "not ICP."
|
|
266
269
|
- **Marketplace supply-side contamination:** >20% of sample rows match
|
|
267
270
|
the brief §14 forbidden side (e.g. Skillsync sample contains
|
|
@@ -55,7 +55,7 @@ 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
60
|
after rubrics and the approved message set are ready. Batch/materialize the
|
|
61
61
|
uploaded CSV into a Sellable lead-list table. Persist the returned
|
|
@@ -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
|
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
This reference governs Step 15 (`auto-execute-messaging`) re-cascade
|
|
4
4
|
behavior when Step 14's validate-sample loop graduates additional rows
|
|
5
|
-
from pending → passed after the first
|
|
6
|
-
already run.
|
|
5
|
+
from pending → passed after the first Generate Message cells have already run.
|
|
7
6
|
|
|
8
7
|
Load whenever Step 15 is about to transition to
|
|
9
8
|
`awaiting-user-greenlight`, and on every resume into Step 15.
|
|
@@ -25,7 +24,7 @@ Re-cascade runs whenever ALL of the following are true:
|
|
|
25
24
|
|
|
26
25
|
1. Step 15 has already observed the initial review-batch message cascade.
|
|
27
26
|
2. A subsequent check of rubric state shows rows that were pending at
|
|
28
|
-
first
|
|
27
|
+
first message-generation pass are now passed.
|
|
29
28
|
3. Those newly-passed rows do NOT yet have generated messages
|
|
30
29
|
(`messagesCount` flat relative to pre-cascade).
|
|
31
30
|
4. Step 15 has NOT yet transitioned to `awaiting-user-greenlight`.
|
|
@@ -14,14 +14,14 @@ Building campaign with {Claude Code or Codex} [Exit watch mode]
|
|
|
14
14
|
{visibleState} {agentIntent}
|
|
15
15
|
|
|
16
16
|
Next: {nextAction}
|
|
17
|
-
{safety?}
|
|
18
17
|
```
|
|
19
18
|
|
|
20
19
|
UI owns the header, driver label, button, progress bar, step count, and static
|
|
21
20
|
stage labels. The driver label comes from the watch URL mode (`mode=claude` or
|
|
22
21
|
`mode=codex`), so do not add separate guide args for it. You own `stage`,
|
|
23
22
|
`headline`, `visibleState`, `agentIntent`, and any exceptional `nextAction`,
|
|
24
|
-
`
|
|
23
|
+
`workerStatuses`, `blockedReason`, or concise `safety` note for blocked/recovery
|
|
24
|
+
states.
|
|
25
25
|
|
|
26
26
|
## Copy Rules
|
|
27
27
|
|
|
@@ -40,6 +40,11 @@ stage labels. The driver label comes from the watch URL mode (`mode=claude` or
|
|
|
40
40
|
sample you are checking, and why that helps this campaign.
|
|
41
41
|
- At filter choice, do not say filtering the batch before rubrics and message approval are saved.
|
|
42
42
|
- Avoid internal terms: MCP, tool, currentStep, workflow table, scout, debug.
|
|
43
|
+
- Treat `safety` as optional internal context, not a visible disclaimer.
|
|
44
|
+
- Do not repeat long negative lists like "no leads import, no enrichment, no
|
|
45
|
+
messages, no sequence, no sending" in routine watch copy. Prefer one concise
|
|
46
|
+
gate phrase only when it matters: "Approval covers scouting/search only" or
|
|
47
|
+
"Next gate: selected-post scrape."
|
|
43
48
|
- Do not invent time estimates.
|
|
44
49
|
|
|
45
50
|
## Stages
|
|
@@ -86,8 +91,7 @@ Default source funnel:
|
|
|
86
91
|
"headline": "Choosing the lead source",
|
|
87
92
|
"visibleState": "The browser is on Pick Provider while Codex explains the source path before opening a provider lane.",
|
|
88
93
|
"agentIntent": "Codex will start with people engaging with relevant LinkedIn posts when that looks plausible, then switch to Sales Nav to find ICP people actively posting on LinkedIn, then search by titles, and use Prospeo for a broader account/contact path. Sales Nav with recent activity remains the first LinkedIn fallback.",
|
|
89
|
-
"nextAction": "Review source"
|
|
90
|
-
"safety": "No leads import until you approve the source."
|
|
94
|
+
"nextAction": "Review source"
|
|
91
95
|
}
|
|
92
96
|
```
|
|
93
97
|
|
|
@@ -99,8 +103,7 @@ Signal Discovery viability handoff:
|
|
|
99
103
|
"headline": "Checking Signal Discovery viability",
|
|
100
104
|
"visibleState": "The browser is moving from Pick Provider into Signal Discovery so the exact posts and sample math are visible.",
|
|
101
105
|
"agentIntent": "Codex is testing whether relevant posts have enough ICP-looking engagers before recommending this as the source.",
|
|
102
|
-
"nextAction": "Review source math"
|
|
103
|
-
"safety": "No leads import until you approve the source."
|
|
106
|
+
"nextAction": "Review source math"
|
|
104
107
|
}
|
|
105
108
|
```
|
|
106
109
|
|
|
@@ -112,8 +115,7 @@ Source direction override:
|
|
|
112
115
|
"headline": "Testing the requested source",
|
|
113
116
|
"visibleState": "The campaign asked for hiring and account signals, so Codex is starting with Prospeo instead of the default LinkedIn engagement path.",
|
|
114
117
|
"agentIntent": "It is checking whether this source has enough reachable ICP-looking people before importing a review batch.",
|
|
115
|
-
"nextAction": "Review source"
|
|
116
|
-
"safety": "No leads import until you approve the source."
|
|
118
|
+
"nextAction": "Review source"
|
|
117
119
|
}
|
|
118
120
|
```
|
|
119
121
|
|
|
@@ -125,8 +127,7 @@ Source fallback:
|
|
|
125
127
|
"headline": "Switching source lanes",
|
|
126
128
|
"visibleState": "The Signal Discovery sample did not show enough ICP-looking engagers for a confident first batch.",
|
|
127
129
|
"agentIntent": "Codex is trying Sales Nav with recent activity so the source can still preserve some buyer activity context.",
|
|
128
|
-
"nextAction": "Review source"
|
|
129
|
-
"safety": "No leads import until you approve the source."
|
|
130
|
+
"nextAction": "Review source"
|
|
130
131
|
}
|
|
131
132
|
```
|
|
132
133
|
|
|
@@ -149,9 +150,8 @@ Source recommendation ready:
|
|
|
149
150
|
"stage": "find-leads",
|
|
150
151
|
"headline": "Review the source in Codex",
|
|
151
152
|
"visibleState": "The browser is showing the evaluated Signal Discovery source with counts and sample quality.",
|
|
152
|
-
"agentIntent": "Approve LinkedIn Engagement or ask for a source change in chat
|
|
153
|
-
"nextAction": "Approve in Codex"
|
|
154
|
-
"safety": "No leads import until you approve the source."
|
|
153
|
+
"agentIntent": "Approve LinkedIn Engagement or ask for a source change in chat.",
|
|
154
|
+
"nextAction": "Approve in Codex"
|
|
155
155
|
}
|
|
156
156
|
```
|
|
157
157
|
|
|
@@ -178,10 +178,9 @@ 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
|
|
183
|
-
"nextAction": "Review batch ready"
|
|
184
|
-
"safety": "This is still a review step; nothing launches or sends."
|
|
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
|
+
"nextAction": "Review batch ready"
|
|
185
184
|
}
|
|
186
185
|
```
|
|
187
186
|
|
|
@@ -199,10 +198,9 @@ After review batch import:
|
|
|
199
198
|
"visibleState": "The first review batch is in the campaign. The visible sample looks mixed enough that filters should be added before message review.",
|
|
200
199
|
"agentIntent": "Codex is asking whether you want to further filter these leads before message review. Skip filters only if the visible rows already look clean.",
|
|
201
200
|
"nextAction": "Choose filters or skip",
|
|
202
|
-
"safety": "Nothing enriches, validates, or sends until the message is ready and approved.",
|
|
203
201
|
"workerStatuses": {
|
|
204
202
|
"leadFitBuilder": "idle",
|
|
205
|
-
"messageDraftBuilder": "
|
|
203
|
+
"messageDraftBuilder": "running"
|
|
206
204
|
}
|
|
207
205
|
}
|
|
208
206
|
```
|
|
@@ -211,7 +209,8 @@ Use this after the selected review rows are present and before filters are
|
|
|
211
209
|
saved. This is add-filters intent, not active filtering. Recommend adding
|
|
212
210
|
filters when the sample is mixed/noisy, tell the user to Choose filters or skip,
|
|
213
211
|
and do not say filtering the batch before rubrics and message approval are
|
|
214
|
-
saved.
|
|
212
|
+
saved. The Message Draft Builder should start immediately after the bounded
|
|
213
|
+
review batch exists; mark it running only when that branch actually started.
|
|
215
214
|
When the user chooses filters, immediately persist `enableICPFilters: true` and
|
|
216
215
|
move to `create-icp-rubric` so the watched app shows Filter Rules while Codex
|
|
217
216
|
defines the rules in chat. After `save_rubrics`, move to `apply-icp-rubric`
|
|
@@ -242,11 +241,28 @@ Review ready:
|
|
|
242
241
|
"headline": "Review the message template",
|
|
243
242
|
"visibleState": "The browser remains on Filter Leads while the message template is reviewed in chat.",
|
|
244
243
|
"agentIntent": "Codex is waiting for approval before saving the template to the campaign brief and queueing enrichment/filtering.",
|
|
245
|
-
"nextAction": "Approve or revise the template"
|
|
246
|
-
"safety": "Codex will only continue after you approve."
|
|
244
|
+
"nextAction": "Approve or revise the template"
|
|
247
245
|
}
|
|
248
246
|
```
|
|
249
247
|
|
|
248
|
+
Template approved, bounded filter test running:
|
|
249
|
+
|
|
250
|
+
```json
|
|
251
|
+
{
|
|
252
|
+
"stage": "fit-message",
|
|
253
|
+
"headline": "Template saved",
|
|
254
|
+
"visibleState": "The browser stays on Filter Leads while the bounded enrichment and filter test runs.",
|
|
255
|
+
"agentIntent": "Codex saved the approved message template, queued the review-batch Enrich Prospect cells, and is waiting for at least one row to pass before moving to Messages.",
|
|
256
|
+
"nextAction": "Move to Messages after a passing row"
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Do not move to Messages immediately after `approve-message`. The visible route
|
|
261
|
+
is already Filter Leads after `save_rubrics`; approving the message only unlocks
|
|
262
|
+
the bounded cascade from that screen. Move to Messages only once at least one
|
|
263
|
+
review-batch row passes and Generate Message cells are ready/running for the
|
|
264
|
+
passing rows.
|
|
265
|
+
|
|
250
266
|
Messages waiting for template:
|
|
251
267
|
|
|
252
268
|
```json
|
|
@@ -255,8 +271,7 @@ Messages waiting for template:
|
|
|
255
271
|
"headline": "Waiting for the template",
|
|
256
272
|
"visibleState": "The fit rules are saved and the message template is still being prepared.",
|
|
257
273
|
"agentIntent": "Codex is waiting until the template can be reviewed.",
|
|
258
|
-
"nextAction": "Review template"
|
|
259
|
-
"safety": "No enrichment, filtering, or Generate Message cells run until the template is approved."
|
|
274
|
+
"nextAction": "Review template"
|
|
260
275
|
}
|
|
261
276
|
```
|
|
262
277
|
|
|
@@ -36,7 +36,7 @@ Example skeleton:
|
|
|
36
36
|
I created the campaign shell with the brief already in it.
|
|
37
37
|
You can watch the lead source, filters, and messages fill in from here.
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
I’ll pause at the next approval gate before sourcing.
|
|
40
40
|
|
|
41
41
|
Watch link: [Open campaign]({watchUrl})
|
|
42
42
|
|
|
@@ -36,10 +36,13 @@ Step 13 — import/confirm review batch only
|
|
|
36
36
|
update_campaign(currentStep=filter-choice)
|
|
37
37
|
|
|
38
38
|
Post-import main thread
|
|
39
|
-
launch
|
|
39
|
+
launch Message Draft Builder immediately after workflowTableId + review rows exist
|
|
40
|
+
launch Lead Fit Builder only after user chooses filters
|
|
40
41
|
save_rubrics({ campaignOfferId, leadScoringRubrics }) after the campaign table exists
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
keep the watched app on Filter Leads after rubrics are saved
|
|
43
|
+
while on Filter Leads, show the message template recommendation from the background Message Draft Builder
|
|
44
|
+
after approve-message, update_campaign_brief writes `## Approved Message Template` with `{{...}}` tokens
|
|
45
|
+
only then start the bounded review-batch cascade
|
|
43
46
|
|
|
44
47
|
Step 14 — kick bounded cascade + observe sample
|
|
45
48
|
queue_cells(cellIds=<review-batch Enrich Prospect cells only>) <-- starts bounded chain
|
|
@@ -58,7 +61,9 @@ Step 15 — observe messaging
|
|
|
58
61
|
get_rows_minimal # confirm passing rows have completed Generate Message cells
|
|
59
62
|
(rare) queue_cells on any pending Generate Message cells
|
|
60
63
|
token-contract spot check via get_rows
|
|
61
|
-
update_campaign(currentStep=
|
|
64
|
+
update_campaign(currentStep=auto-execute-messaging) with review-ready narration
|
|
65
|
+
ask the user to approve generated review-batch messages before Settings
|
|
66
|
+
only after approval: update_campaign(currentStep=awaiting-user-greenlight)
|
|
62
67
|
(generate_messages is NOT an MCP tool; messages come from the cascade)
|
|
63
68
|
|
|
64
69
|
Step 16 — awaiting-user-greenlight
|
|
@@ -144,7 +149,9 @@ what changed and orient the user to what the watch link will show next —
|
|
|
144
149
|
reuse the v1 `create-campaign` watch-mode pattern verbatim.
|
|
145
150
|
|
|
146
151
|
Resume currentStep names covered by this tail: `"auto-execute-leads"`,
|
|
147
|
-
`"
|
|
152
|
+
`"apply-icp-rubric"` (the visible Filter Leads home for the logical
|
|
153
|
+
`validate-sample` loop), `"validate-sample"` (legacy resumes only),
|
|
154
|
+
`"auto-execute-messaging"`,
|
|
148
155
|
`"awaiting-user-greenlight"`, `"settings"`, `"sequence"`, `"send"`, and
|
|
149
156
|
`"running"`. New mint-early runs normally
|
|
150
157
|
enter Step 13 from `"confirm-lead-list"`; the `"auto-execute-leads"` string is
|
|
@@ -273,10 +280,12 @@ caller or start the workflow-table cascade too early. The cascade starts in
|
|
|
273
280
|
Step 14 only after `save_rubrics` and `update_campaign_brief` have both
|
|
274
281
|
succeeded.
|
|
275
282
|
|
|
276
|
-
## Step 14: validate-sample (loop)
|
|
283
|
+
## Step 14: validate-sample (logical loop on Filter Leads)
|
|
277
284
|
|
|
278
|
-
Entered
|
|
279
|
-
|
|
285
|
+
Entered after the message template is approved while the watched campaign is
|
|
286
|
+
already on `CampaignOffer.currentStep === "apply-icp-rubric"` / Filter Leads.
|
|
287
|
+
Do not route to a visible `validate-sample` step. Full decision tree lives in
|
|
288
|
+
`references/sample-validation-loop.md`.
|
|
280
289
|
|
|
281
290
|
**Step 14 starts the bounded cascade, then observes it.** Step 13 imported the
|
|
282
291
|
review batch only. After `save_rubrics` and the approved message template are
|
|
@@ -381,8 +390,9 @@ Template`. If it does not, fail before the cascade runs. Do not repair
|
|
|
381
390
|
5. If the sample fails the token contract, diagnose brief-vs-list
|
|
382
391
|
(same revision loop as Step 14) and escalate if over
|
|
383
392
|
`maxRevisionRounds`.
|
|
384
|
-
6. On success, `
|
|
385
|
-
|
|
393
|
+
6. On success, keep `currentStep: "auto-execute-messaging"` and ask the user
|
|
394
|
+
to approve the generated review-batch messages. Only that approval may move
|
|
395
|
+
the campaign to Settings / `awaiting-user-greenlight`.
|
|
386
396
|
|
|
387
397
|
**Do NOT hand-write message bodies via `update_cell`.** `update_cell`
|
|
388
398
|
is reachable for legitimate operator overrides AFTER the tail hands
|
|
@@ -428,8 +438,11 @@ strings, which is why Step 16 requires Step 15 to be complete.
|
|
|
428
438
|
6. If the sample fails the token contract or critique, diagnose +
|
|
429
439
|
loop the same way Step 14 does (brief-vs-list), subject to the same
|
|
430
440
|
`maxRevisionRounds` cap.
|
|
431
|
-
7. On success, `
|
|
432
|
-
|
|
441
|
+
7. On success, keep `currentStep: "auto-execute-messaging"`, show that the
|
|
442
|
+
review-batch messages are ready in Messages, and ask for approval before
|
|
443
|
+
Settings. Only after the user approves those generated messages should
|
|
444
|
+
`update_campaign({ campaignId, currentStep: "awaiting-user-greenlight" })`
|
|
445
|
+
run.
|
|
433
446
|
|
|
434
447
|
Critique failure modes NEVER escalate. A critic timeout, a total
|
|
435
448
|
timeout, a budget trip, a fake-proof rejection, or an unsupported-
|
|
@@ -451,7 +464,7 @@ Shape:
|
|
|
451
464
|
`get_campaign_navigation_state` when available to confirm the watch link is
|
|
452
465
|
visibly on Settings.
|
|
453
466
|
4. Explain why the sender matters: Sellable needs a connected LinkedIn sender
|
|
454
|
-
|
|
467
|
+
for launch. Explain Slack reply review before launch: replies
|
|
455
468
|
and approvals need a place the team will actually monitor, so Slack should be
|
|
456
469
|
connected or intentionally skipped before launch.
|
|
457
470
|
5. If no connected sender exists, surface a direct Settings link:
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: load-voice
|
|
3
|
+
description: Load Sellable voice/company memory before answering questions, writing posts, applications, replies, or other copy in the user's voice.
|
|
4
|
+
visibility: public
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Glob
|
|
8
|
+
- Grep
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Load Sellable Voice
|
|
12
|
+
|
|
13
|
+
<role>
|
|
14
|
+
You are the Sellable voice loader. Your job is to read the user's durable
|
|
15
|
+
Sellable voice/company memory into the current thread before drafting,
|
|
16
|
+
answering, rewriting, reviewing, or calibrating copy in the user's voice.
|
|
17
|
+
|
|
18
|
+
This is a read-only usage workflow. Do not interview by default, do not write
|
|
19
|
+
memory files, and do not update `.sellable/**` unless the user explicitly asks
|
|
20
|
+
to switch into `$sellable:interview`.
|
|
21
|
+
</role>
|
|
22
|
+
|
|
23
|
+
<default_use_cases>
|
|
24
|
+
Use this workflow when the user asks to:
|
|
25
|
+
|
|
26
|
+
- answer questions on behalf of them
|
|
27
|
+
- write or rewrite a LinkedIn post
|
|
28
|
+
- answer an application, investor, customer, or sales question
|
|
29
|
+
- draft a sales reply, objection response, cold note, or website line
|
|
30
|
+
- review whether copy sounds like them
|
|
31
|
+
- "use my voice", "load my voice", "answer like me", or "write this as me"
|
|
32
|
+
</default_use_cases>
|
|
33
|
+
|
|
34
|
+
<load_order>
|
|
35
|
+
Read only relevant files. Start with the active `.sellable/configs` memory
|
|
36
|
+
layer, not random repo docs.
|
|
37
|
+
|
|
38
|
+
If `.sellable/configs` is not visible from the current working directory, use
|
|
39
|
+
`Glob` to find `**/.sellable/configs/core/my-company.md`, excluding
|
|
40
|
+
`node_modules`, `.next`, `dist`, and `.git`, then use the nearest parent as the
|
|
41
|
+
Sellable memory root.
|
|
42
|
+
|
|
43
|
+
## Core Voice And Judgment
|
|
44
|
+
|
|
45
|
+
Read these when present:
|
|
46
|
+
|
|
47
|
+
- `.sellable/configs/core/about-me.md`
|
|
48
|
+
- `.sellable/configs/core/anti-ai-writing-style.md`
|
|
49
|
+
- `.sellable/configs/core/decision-rules.md`
|
|
50
|
+
- `.sellable/configs/core/context-modes.md`
|
|
51
|
+
|
|
52
|
+
## Company Truth And Proof
|
|
53
|
+
|
|
54
|
+
Read these when present:
|
|
55
|
+
|
|
56
|
+
- `.sellable/configs/core/my-company.md`
|
|
57
|
+
- `.sellable/configs/core/answer-bank.md`
|
|
58
|
+
- `.sellable/configs/core/proof-ledger.md`
|
|
59
|
+
- `.sellable/configs/core/story-bank.md`
|
|
60
|
+
- `.sellable/configs/core/wins-ledger.md`
|
|
61
|
+
|
|
62
|
+
## Writing-Specific Guidance
|
|
63
|
+
|
|
64
|
+
Read these when present and relevant to the task:
|
|
65
|
+
|
|
66
|
+
- `.sellable/configs/writing/styleguide-core.md`
|
|
67
|
+
- `.sellable/configs/writing/comments.md`
|
|
68
|
+
|
|
69
|
+
## Transcript Or Topic Context
|
|
70
|
+
|
|
71
|
+
Do not bulk-read raw transcripts. If the user asks about a specific topic,
|
|
72
|
+
story, sales call, customer, market view, or correction, first read:
|
|
73
|
+
|
|
74
|
+
- `.sellable/configs/core/transcripts/INDEX.md`
|
|
75
|
+
- the most relevant file under `.sellable/configs/core/transcripts/topics/`
|
|
76
|
+
|
|
77
|
+
Only read raw archives under `.sellable/interviews/**` when the index/topic file
|
|
78
|
+
points to one and the current task needs that source detail.
|
|
79
|
+
</load_order>
|
|
80
|
+
|
|
81
|
+
<operating_rules>
|
|
82
|
+
|
|
83
|
+
- Keep the loader lightweight. The first pass should usually be 6-10 files, not
|
|
84
|
+
every file under `.sellable`.
|
|
85
|
+
- Apply the loaded profile silently after a short confirmation. Do not paste a
|
|
86
|
+
long summary of the memory unless the user asks for one.
|
|
87
|
+
- If the user already gave a concrete writing task, load the memory and then do
|
|
88
|
+
the task. Do not stop at "I loaded the files."
|
|
89
|
+
- If the user only asked to load voice, say what you loaded, name the strongest
|
|
90
|
+
active rules in 3-6 bullets, then ask what they want drafted, answered, or
|
|
91
|
+
reviewed.
|
|
92
|
+
- If exact proof, numbers, customer names, or timelines are not confirmed in
|
|
93
|
+
the loaded memory, preserve that uncertainty. Do not launder uncertain proof
|
|
94
|
+
into clean claims.
|
|
95
|
+
- Use the current `context-modes.md` behavior for the requested surface:
|
|
96
|
+
LinkedIn post, sales reply, website, investor/application answer, outbound, or
|
|
97
|
+
internal strategy.
|
|
98
|
+
- When answering on behalf of the user, write in first person unless the user
|
|
99
|
+
asks otherwise.
|
|
100
|
+
- If a question cannot be answered from memory, make the smallest honest
|
|
101
|
+
assumption or ask one specific follow-up. Do not invent private history,
|
|
102
|
+
metrics, customer facts, or beliefs.
|
|
103
|
+
- If the user says the output is wrong, ask what feels off and accept messy
|
|
104
|
+
dictated notes. Use that correction in the current thread. If they want the
|
|
105
|
+
correction saved durably, route them to `$sellable:interview`.
|
|
106
|
+
</operating_rules>
|
|
107
|
+
|
|
108
|
+
<response_shape>
|
|
109
|
+
After loading memory, use this shape when there is no concrete draft task yet:
|
|
110
|
+
|
|
111
|
+
```text
|
|
112
|
+
I loaded your Sellable voice/company memory from {n} files. I’ll apply it
|
|
113
|
+
silently unless you override it.
|
|
114
|
+
|
|
115
|
+
The active rules I’m carrying forward:
|
|
116
|
+
- ...
|
|
117
|
+
|
|
118
|
+
What should I answer, write, or review?
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
When there is already a concrete task, keep the confirmation to one sentence,
|
|
122
|
+
then produce the answer or draft.
|
|
123
|
+
</response_shape>
|
|
124
|
+
|
|
125
|
+
<quality_bar>
|
|
126
|
+
The result should feel like the user has a standing voice file in the thread:
|
|
127
|
+
specific, current, proof-safe, and ready to answer on their behalf without
|
|
128
|
+
forcing them to re-explain the same voice/company context every time.
|
|
129
|
+
</quality_bar>
|