@sellable/mcp 0.1.212 → 0.1.213

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.
Files changed (35) hide show
  1. package/README.md +7 -7
  2. package/agents/post-find-leads-message-scout.md +33 -13
  3. package/dist/engage-memory.js +0 -5
  4. package/dist/identity-memory.js +0 -4
  5. package/dist/tools/engage-memory.js +2 -2
  6. package/dist/tools/leads.js +7 -3
  7. package/dist/tools/prompts.js +3 -2
  8. package/package.json +1 -1
  9. package/skills/create-campaign/context/learnings.md +1 -1
  10. package/skills/create-campaign/references/brief-template.md +2 -2
  11. package/skills/create-campaign-brief/references/brief-template.md +2 -2
  12. package/skills/create-campaign-brief/references/draft-lifecycle.md +1 -1
  13. package/skills/create-campaign-brief/references/examples/briefs/gelee.md +2 -2
  14. package/skills/create-campaign-brief/references/examples/briefs/superpower.md +41 -28
  15. package/skills/create-campaign-brief/references/phase75-active-runtime-message-pack.md +12 -9
  16. package/skills/create-campaign-v2/SKILL.md +4 -0
  17. package/skills/create-campaign-v2/references/ai-tells.md +51 -16
  18. package/skills/create-campaign-v2/references/approval-gate-framing.md +1 -1
  19. package/skills/create-campaign-v2/references/gold-standard-message-examples.md +30 -16
  20. package/skills/create-campaign-v2/references/gold-standard-message-patterns.md +36 -1
  21. package/skills/create-campaign-v2/references/gold-standard-runtime-message-pack.md +252 -0
  22. package/skills/create-campaign-v2/references/thomas-revision-filters.md +17 -7
  23. package/skills/create-campaign-v2/references/validation-criteria.md +8 -5
  24. package/skills/create-campaign-v2-validation/SKILL.md +17 -1
  25. package/skills/create-post/SKILL.md +27 -27
  26. package/skills/engage/SKILL.md +12 -12
  27. package/skills/engage/core/README.md +14 -14
  28. package/skills/find-leads/SKILL.md +1 -1
  29. package/skills/generate-messages/SKILL.md +215 -90
  30. package/skills/interview/SKILL.md +24 -24
  31. package/skills/interview/references/legacy-linkedin-interview.md +12 -12
  32. package/skills/interview/references/reference-curation.md +4 -4
  33. package/skills/interview/references/voice-capture-method.md +1 -1
  34. package/skills/load-voice/SKILL.md +21 -25
  35. package/skills/research/SKILL.md +1 -1
package/README.md CHANGED
@@ -334,12 +334,12 @@ with outcomes, and tracked people (LinkedIn profiles), all scoped by workspace.
334
334
 
335
335
  - Auth + active workspace: `~/.sellable/config.json` (or `SELLABLE_CONFIG_PATH`; old `$CODEX_HOME/sellable.json`, `~/.codex/sellable.json`, and `~/.claude/sellable.json` files remain compatibility fallbacks)
336
336
  - Engage memory (style guide + searches + tracked people): `sellable.engage.json` (or `SELLABLE_ENGAGE_MEMORY_PATH`)
337
- - Team-editable, project-local configs (recommended to edit in git):
338
- - `./.sellable/configs/writing/styleguide.md`
339
- - `./.sellable/configs/audience/icp-filters.md`
340
- - `./.sellable/configs/proof/claims.md`
341
- - `./.sellable/configs/discovery/influencers.md`
342
- - `./.sellable/configs/discovery/post-filters.md`
337
+ - Team-editable durable configs (home-level source of truth):
338
+ - `~/.sellable/configs/writing/styleguide.md`
339
+ - `~/.sellable/configs/audience/icp-filters.md`
340
+ - `~/.sellable/configs/proof/claims.md`
341
+ - `~/.sellable/configs/discovery/influencers.md`
342
+ - `~/.sellable/configs/discovery/post-filters.md`
343
343
 
344
344
  Files under `mcp/sellable/skills/**/core/*` are **package repo files**, not the intended user config surface.
345
345
 
@@ -352,7 +352,7 @@ Primary public entrypoint for the approval-gated campaign creation flow.
352
352
  ### interview
353
353
 
354
354
  Public identity/company memory interview. Builds durable core files under
355
- `./.sellable/configs/core/**`, raw archives under `./.sellable/interviews/**`,
355
+ `~/.sellable/configs/core/**`, raw archives under `~/.sellable/interviews/**`,
356
356
  and reusable answer/proof/story/transcript/reference memory for downstream
357
357
  Sellable writing workflows.
358
358
 
@@ -60,9 +60,11 @@ required message reference cannot be loaded through the MCP asset loader, return
60
60
  `get_subskill_prompt({ subskillName: "generate-messages" })`
61
61
 
62
62
  3. Load every packaged reference asset required by that prompt's Reference Asset
63
- Loading section with `get_subskill_asset`. If a required asset cannot load
64
- through the MCP asset loader, return `blocked` or `retry-needed` instead of
65
- drafting from memory.
63
+ Loading section with `get_subskill_asset`: load the required pre-draft reference pack before
64
+ drafting, load final-pass references before approval, and `ai-tells.md` is part of the required pack
65
+ and never optional. If a required asset cannot
66
+ load through the MCP asset loader, return `blocked` / `retry-needed`; do not draft from
67
+ memory or from the prompt alone.
66
68
  4. Build positioning in a compact working note: buyer, pain, product, mechanism,
67
69
  proof boundary, source-use rule, and CTA.
68
70
  5. Draft 3 distinct first-message options: signal-led, product/mechanism-led,
@@ -89,6 +91,7 @@ Return the following to the parent thread:
89
91
 
90
92
  - proposed first-message template using supported `{{...}}` tokens
91
93
  - token fill rules and fallbacks
94
+ - `Reference Asset Loading` note naming which assets were used and why
92
95
  - one rendered good-fill sample for a plausible passing campaign-table row
93
96
  - message-draft runtime status: `ready`, `blocked`, `retry-needed`, or `stale`
94
97
  - approve-or-revise recommendation
@@ -178,16 +181,33 @@ own revision. The parent renders the revised template and waits for
178
181
  - Engagement-source personalization is a special case, not the default opener.
179
182
  Do not write `saw you {{engagement_context}} on {{post_context}}`, `saw you
180
183
  reacted to`, `saw you engaging with`, or equivalent source-citation copy as a
181
- default hook. For LinkedIn-post-sourced campaigns, you may reference the
182
- source when it explains why the note exists, but keep it topic-level, not
183
- activity-log-level. Good: `saw you in a few conversations around [topic], so
184
- hope this is relevant`, `saw you in a few conversations about [topic], so
185
- may be off, but this seemed relevant`, `saw you might be interested in [topic],
186
- so hope this is relevant`, `hope this is relevant if [topic] is on your plate`,
187
- or `saw you raise your hand for [topic], so figured this was (hopefully) worth sending`.
184
+ default hook. Sender-owned post sources are different: if the source post was
185
+ authored by the sender/client and the row proves a reaction/comment, prefer a
186
+ light first-person acknowledgment such as `appreciate you showing some love on
187
+ my post about [topic]` or `thanks for showing support on my [topic] post`.
188
+ Do not name a comment unless the row proves comment text, and do not infer
189
+ buyer intent from the reaction. Follow that acknowledgment with a soft
190
+ relevance bridge before any broad problem or product line. Good:
191
+ `figured this might be relevant if [channel/workflow] is becoming more of a
192
+ [GTM/pipeline/content] channel for [company/team]`. Bad: jumping directly
193
+ from `appreciate you showing some love...` to `a lot of B2B teams...` or
194
+ `most teams...`; that reads stitched together. Every line must make the next
195
+ line feel earned: source/post signal -> relevance bridge -> product/problem
196
+ -> next step. If adjacent lines could be swapped, deleted, or joined with
197
+ `anyway` without changing the meaning, rewrite the bridge or cut the orphan
198
+ line. For third-party LinkedIn-post-sourced
199
+ campaigns, keep the source topic-level. Good: `saw you in a few conversations
200
+ around [topic], so hope this is relevant`, `saw you in a few conversations
201
+ about [topic], so may be off, but this seemed relevant`, `saw you might be
202
+ interested in [topic], so hope this is relevant`, `hope this is relevant if
203
+ [topic] is on your plate`, or `found you in a thread about [topic], so may be
204
+ off, but this seemed relevant`. Only use `saw you raise your hand for [topic],
205
+ so figured this was (hopefully) worth sending` when the source was an explicit
206
+ lead-magnet comment, reply, or opt-in.
188
207
  The cheekier `saw you raise your hand for [topic] (creepy to reach out based
189
208
  on that, i know) - but this felt too on the nose to ignore` version is also
190
- allowed when the sender's voice can carry it. Bad: `you commented on...`, `you reacted
209
+ allowed only for explicit lead-magnet comments, replies, or opt-ins and when the
210
+ sender's voice can carry it. Bad: `you commented on...`, `you reacted
191
211
  to...`, `saw you engaging with...`, `your LinkedIn activity...`, `you might
192
212
  not remember the thread...`, or `found you through [source] and your role
193
213
  looked close...`. Otherwise omit the engagement signal and use role/company/problem context.
@@ -196,9 +216,9 @@ looked close...`. Otherwise omit the engagement signal and use role/company/prob
196
216
  topic looked close` are blocked. If the source is too weak, omit it.
197
217
  - Do not assert fit from title/company. `Your [role] role at [company] looked
198
218
  close to this problem` is blocked. Keep the apologetic uncertainty instead:
199
- `may be off, but if [workflow] is anywhere near your lane...`.
219
+ `may be off, but if [workflow] is relevant to what you're working on...`.
200
220
  - Low-pressure relevance opt-outs are allowed when they do not defend the
201
- source: `p.s. if this is nowhere near your outbound workflow, ignore me`.
221
+ source: `p.s. if this is not relevant to your outbound workflow, ignore me`.
202
222
  - Do not use `Caught` as opener language. It reads unnatural in LinkedIn
203
223
  outreach.
204
224
  - Do not describe the sender in third person inside the outbound message.
@@ -8,11 +8,6 @@ function resolveConfigsDir() {
8
8
  if (process.env.SELLABLE_CONFIGS_DIR) {
9
9
  candidates.push(path.resolve(process.env.SELLABLE_CONFIGS_DIR));
10
10
  }
11
- // Same resolution strategy as skills.ts
12
- if (process.argv[1]) {
13
- candidates.push(path.resolve(path.dirname(process.argv[1]), "../../.sellable/configs"));
14
- }
15
- candidates.push(path.resolve(process.cwd(), ".sellable/configs"));
16
11
  candidates.push(path.resolve(os.homedir(), ".sellable/configs"));
17
12
  for (const candidate of candidates) {
18
13
  if (fs.existsSync(candidate)) {
@@ -20,10 +20,6 @@ export function resolveIdentityConfigsDir() {
20
20
  if (process.env.SELLABLE_CONFIGS_DIR) {
21
21
  candidates.push(path.resolve(process.env.SELLABLE_CONFIGS_DIR));
22
22
  }
23
- if (process.argv[1]) {
24
- candidates.push(path.resolve(path.dirname(process.argv[1]), "../../.sellable/configs"));
25
- }
26
- candidates.push(path.resolve(process.cwd(), ".sellable/configs"));
27
23
  candidates.push(path.resolve(os.homedir(), ".sellable/configs"));
28
24
  for (const candidate of candidates) {
29
25
  if (fs.existsSync(candidate)) {
@@ -2,7 +2,7 @@ import { copySenderConfig, getEngageMemory, migrateFlatConfigs, recordProvenSear
2
2
  export const engageMemoryToolDefinitions = [
3
3
  {
4
4
  name: "get_engage_memory",
5
- description: "Load backward-compatible engage memory from .sellable/configs/: style guide, proven search keywords, tracked people, plus optional core identity/company memory. All data lives in readable markdown files the user can also edit directly. When senderId is provided, reads compatibility overrides from senders/{senderId}/ with flat-path fallback.",
5
+ description: "Load backward-compatible engage memory from ~/.sellable/configs/: style guide, proven search keywords, tracked people, plus optional core identity/company memory. All data lives in readable markdown files the user can also edit directly. When senderId is provided, reads compatibility overrides from senders/{senderId}/ with flat-path fallback.",
6
6
  inputSchema: {
7
7
  type: "object",
8
8
  properties: {
@@ -17,7 +17,7 @@ export const engageMemoryToolDefinitions = [
17
17
  },
18
18
  {
19
19
  name: "set_engage_style_guide",
20
- description: "Write the user's commenting style guide. When senderId is provided, writes to .sellable/configs/senders/{senderId}/styleguide-core.md. Otherwise writes to .sellable/configs/writing/styleguide-core.md.",
20
+ description: "Write the user's commenting style guide. When senderId is provided, writes to ~/.sellable/configs/senders/{senderId}/styleguide-core.md. Otherwise writes to ~/.sellable/configs/writing/styleguide-core.md.",
21
21
  inputSchema: {
22
22
  type: "object",
23
23
  properties: {
@@ -1365,7 +1365,7 @@ export const leadToolDefinitions = [
1365
1365
  },
1366
1366
  limit: {
1367
1367
  type: "number",
1368
- description: "Max posts (default 25, max 50). Used for profile search.",
1368
+ description: "Max posts (default 25, max 50). Used for profile or company search.",
1369
1369
  },
1370
1370
  headlineICPCriteria: {
1371
1371
  type: "array",
@@ -3177,7 +3177,9 @@ export async function selectPromisingPosts(input) {
3177
3177
  const { campaignOfferId, selections, headlineICPCriteria, selectionMode, mode, scrapePlanMode, targetEngagerCount, maxPostsToScrape, } = input;
3178
3178
  const effectiveMode = selectionMode ?? mode ?? "replace";
3179
3179
  const effectiveScrapePlanMode = scrapePlanMode ??
3180
- (targetEngagerCount || maxPostsToScrape ? "capacity-target" : "all-selected");
3180
+ (targetEngagerCount || maxPostsToScrape
3181
+ ? "capacity-target"
3182
+ : "all-selected");
3181
3183
  if (selections.length > MAX_SIGNAL_DISCOVERY_POSTS) {
3182
3184
  return {
3183
3185
  success: false,
@@ -3249,7 +3251,9 @@ export async function selectPromisingPosts(input) {
3249
3251
  }
3250
3252
  const recommendation = buildSignalDiscoverySourceRecommendation({
3251
3253
  selectedPosts: Array.from(selectedByUrl.values()),
3252
- targetEngagerCount: effectiveScrapePlanMode === "capacity-target" ? targetEngagerCount : null,
3254
+ targetEngagerCount: effectiveScrapePlanMode === "capacity-target"
3255
+ ? targetEngagerCount
3256
+ : null,
3253
3257
  maxPostsToScrape: effectiveScrapePlanMode === "capacity-target" ? maxPostsToScrape : null,
3254
3258
  });
3255
3259
  sourceRecommendation = recommendation.message;
@@ -328,7 +328,7 @@ export function getPostFindLeadsScoutRegistry() {
328
328
  "basis.workflowTableId",
329
329
  "basis.sampleRowIds",
330
330
  ],
331
- promptRequired: 'Load current campaign brief/table state through scoped tools, then get_subskill_prompt({ subskillName: "generate-messages" }) for all chunks. Load every asset named in the generate-messages Reference Asset Loading pack through get_subskill_asset. Before returning, load get_subskill_prompt({ subskillName: "create-campaign-v2-validation" }) and use it as the final internal message-validation gate. Do not use shell/local filesystem reads, repo paths, plugin-cache paths, or /Users paths for message references. If required prompts/assets cannot be loaded through MCP tools, return blocked/retry-needed instead of drafting from memory.',
331
+ promptRequired: 'Load current campaign brief/table state through scoped tools, then get_subskill_prompt({ subskillName: "generate-messages" }) for all chunks. Follow its Reference Asset Loading step and load the Reference Asset Loading pack: the required pre-draft reference pack plus every required final-pass asset through get_subskill_asset; ai-tells.md is required and never optional. Before returning, load get_subskill_prompt({ subskillName: "create-campaign-v2-validation" }) and use it as the final internal message-validation gate. Do not use shell/local filesystem reads, repo paths, plugin-cache paths, or /Users paths for message references. If required prompts/assets cannot be loaded through MCP tools, return blocked/retry-needed instead of drafting from memory; fail closed instead of drafting from the prompt alone.',
332
332
  basisFields: [
333
333
  "campaignId",
334
334
  "workflowTableId",
@@ -340,6 +340,7 @@ export function getPostFindLeadsScoutRegistry() {
340
340
  messageDraftOutputFields: [
341
341
  "templateRecommendation",
342
342
  "tokenFillRules",
343
+ "referenceAssetLoading",
343
344
  "renderedGoodSample",
344
345
  "revisionNotes when user feedback triggered a revision",
345
346
  "status",
@@ -356,7 +357,7 @@ export function getPostFindLeadsScoutRegistry() {
356
357
  usage: {
357
358
  codex: "After confirm_lead_list copies source rows and the initial campaign-table execution slice exists, ask the filter-choice question immediately. Do not spawn anything before that question. After the answer, launch only Message Drafting whenever Codex agent-launch policy is satisfied. If filters are chosen, the parent stays on Filter Rules and drafts/saves rubrics with MCP tools while Message Drafting runs in the background. If filters are skipped, move to Messages/message review after Message Drafting is ready. Treat YOLO/autonomous mode as campaign-scoped permission for this single post-import worker. If the user has not enabled YOLO and has not explicitly asked for background agents/subagents/parallel agents/delegation/message bg agent in this campaign, ask once before loading the long message prompt in the parent. If permission is granted and the named Message Drafting custom agent is unavailable, spawn a generic gpt-5.5 xhigh Message Drafting background agent with the same lean campaign/table basis.",
358
359
  claude: "After confirm_lead_list copies source rows and the initial campaign-table execution slice exists, ask the filter-choice question immediately. Do not invoke any Task/Agent before that question. After the answer, invoke only Message Drafting. If filters are chosen, parent drafts/saves rubrics with MCP tools while Message Drafting runs, asks filter approval, then joins Message Drafting. If filters are skipped, invoke only Message Drafting and move to Messages/message review.",
359
- parentThreadRule: 'The only normal background worker is Message Drafting; source work and filter work stay in the parent thread with MCP tools. After the filter-choice answer, launch post-find-leads-message-scout only. If filters are chosen, the parent thread remains the filter writer: keep the browser on Filter Rules, load the filter reference, draft/save rubrics through MCP tools, ask filter approval, then move to Filter Leads while waiting for Message Drafting if needed. Do not move into message review, queue cells, or call update_campaign_brief until saved filters are approved when filters are enabled and messageDraftRecommendation is ready. If filters are skipped, launch only Message Drafting. In Codex, YOLO/autonomous mode counts as campaign-scoped permission for this single post-import worker; if the user has not enabled YOLO and has not explicitly asked for background agents/subagents/parallel agents/delegation/message bg agent in this campaign, ask once for permission before loading the long message prompt in the parent. If Message Drafting is allowed but the named worker is unavailable, use a generic gpt-5.5 xhigh Message Drafting background agent. Do not silently fall back to parent-thread message drafting. The Message Drafting handoff must be lean: campaignId, workflowTableId, brief summary, source summary/source-use rule, and 3-5 sample workflow-table rows with rowId/name/title/company/signal; optional campaignName, selectedLeadListId, and filter choice are allowed. Do not paste copied row counts, brief hashes, review-batch hashes, full reviewBatchRowIds, broad row data, or local debug artifacts into the message spawn prompt. The message branch must load current campaign brief/context, provided sample rows, the full generate-messages prompt, every referenced asset through get_subskill_asset, and before returning get_subskill_prompt({ subskillName: "create-campaign-v2-validation" }) for the internal validation gate. Local markdown/json files are not normal-path inputs. Message reference assets must be loaded with get_subskill_asset from the installed MCP package; do not use shell/local filesystem reads, repo paths, plugin-cache paths, or /Users paths to satisfy message references. The filter-choice question is the first post-import user gate; do not load this registry or filter references before it. Message drafting starts after the filter-choice answer and must reject mismatched workflowTableId/campaign/workspace input. Do not use any alternate or examples-only message prompt. User copy feedback, message QA, or rewrite requests before approve-message must be routed back to Message Drafting with the current recommendation, lean campaign/table basis, and latest user text; the parent must not rewrite or QA the template from memory and must not call update_campaign_brief before approve-message. The worker validates internally and returns only templateRecommendation, tokenFillRules, renderedGoodSample, status, approveOrReviseRecommendation, validationStatus, outputAt, outputHash, and blocked/retry detail. Do not render renderedFallbackSample, concerns, or a qaReceipt on the normal happy path. On the filter path, the parent thread keeps the browser on Filter Rules after save_rubrics so the user can approve the saved criteria; only then move to Filter Leads, show `Filters saved + waiting for message approval`, and wait there for message approval. Enrichment, filtering, Generate Message cells, sender setup, sequence attach, and launch wait for template approval on the Use Template path. On the skip path, move to Messages/message review and wait for message approval before enrichment or Settings. Do not render message review from checklist or shortcut instructions; message review requires a messageDraftRecommendation whose basis proves the generate-messages prompt, assets, and validation prompt ran for the current campaign/table execution slice. Do not automatically rerun Message Drafting after filters/enrichment finish; show the initial draft by default and offer an enriched rewrite only with explicit user opt-in.',
360
+ parentThreadRule: 'The only normal background worker is Message Drafting; source work and filter work stay in the parent thread with MCP tools. After the filter-choice answer, launch post-find-leads-message-scout only. If filters are chosen, the parent thread remains the filter writer: keep the browser on Filter Rules, load the filter reference, draft/save rubrics through MCP tools, ask filter approval, then move to Filter Leads while waiting for Message Drafting if needed. Do not move into message review, queue cells, or call update_campaign_brief until saved filters are approved when filters are enabled and messageDraftRecommendation is ready. If filters are skipped, launch only Message Drafting. In Codex, YOLO/autonomous mode counts as campaign-scoped permission for this single post-import worker; if the user has not enabled YOLO and has not explicitly asked for background agents/subagents/parallel agents/delegation/message bg agent in this campaign, ask once for permission before loading the long message prompt in the parent. If Message Drafting is allowed but the named worker is unavailable, use a generic gpt-5.5 xhigh Message Drafting background agent. Do not silently fall back to parent-thread message drafting. The Message Drafting handoff must be lean: campaignId, workflowTableId, brief summary, source summary/source-use rule, and 3-5 sample workflow-table rows with rowId/name/title/company/signal; optional campaignName, selectedLeadListId, and filter choice are allowed. Do not paste copied row counts, brief hashes, review-batch hashes, full reviewBatchRowIds, broad row data, or local debug artifacts into the message spawn prompt. The message branch must load current campaign brief/context, provided sample rows, the full generate-messages prompt, follow Reference Asset Loading, load the required pre-draft reference pack before drafting, load every referenced asset through get_subskill_asset, include ai-tells.md because it is never optional, and before returning get_subskill_prompt({ subskillName: "create-campaign-v2-validation" }) for the internal validation gate. The branch must return blocked/retry-needed if required assets cannot be loaded. Local markdown/json files are not normal-path inputs. Message reference assets must be loaded with get_subskill_asset from the installed MCP package; do not use shell/local filesystem reads, repo paths, plugin-cache paths, or /Users paths to satisfy message references. The filter-choice question is the first post-import user gate; do not load this registry or filter references before it. Message drafting starts after the filter-choice answer and must reject mismatched workflowTableId/campaign/workspace input. Do not use any alternate or examples-only message prompt. User copy feedback, message QA, or rewrite requests before approve-message must be routed back to Message Drafting with the current recommendation, lean campaign/table basis, and latest user text; the parent must not rewrite or QA the template from memory and must not call update_campaign_brief before approve-message. The worker validates internally and returns only templateRecommendation, tokenFillRules, referenceAssetLoading, renderedGoodSample, status, approveOrReviseRecommendation, validationStatus, outputAt, outputHash, and blocked/retry detail. Do not render renderedFallbackSample, concerns, or a qaReceipt on the normal happy path. On the filter path, the parent thread keeps the browser on Filter Rules after save_rubrics so the user can approve the saved criteria; only then move to Filter Leads, show `Filters saved + waiting for message approval`, and wait there for message approval. Enrichment, filtering, Generate Message cells, sender setup, sequence attach, and launch wait for template approval on the Use Template path. On the skip path, move to Messages/message review and wait for message approval before enrichment or Settings. Do not render message review from checklist or shortcut instructions; message review requires a messageDraftRecommendation whose basis proves the generate-messages prompt, assets, and validation prompt ran for the current campaign/table execution slice. Do not automatically rerun Message Drafting after filters/enrichment finish; show the initial draft by default and offer an enriched rewrite only with explicit user opt-in.',
360
361
  },
361
362
  };
362
363
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.212",
3
+ "version": "0.1.213",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",
@@ -4,7 +4,7 @@ This log captures what has worked in real campaigns.
4
4
 
5
5
  Entries should be short, specific, and based on observed outcomes.
6
6
 
7
- **Cross-skill learnings** that would help other skills (engage, create-post) should ALSO be written to `.sellable/insights/cross-skill.md` so the entire system learns.
7
+ **Cross-skill learnings** that would help other skills (engage, create-post) should ALSO be written to `~/.sellable/insights/cross-skill.md` so the entire system learns.
8
8
 
9
9
  ## Log
10
10
 
@@ -41,8 +41,8 @@ Example: "In a 15-minute call, we will audit your top 10 accounts and show where
41
41
  - **Bridge to:** [How it connects to their pain]
42
42
  - **Avoid:** [Generic phrases to skip - "best-in-class", "industry-leading", etc.]
43
43
  - **Voice:** [Reference core memory / composed engage memory first. Use legacy writing memory only as fallback.]
44
- - **Outbound rules:** [Reference `.sellable/configs/writing/outbound.md` if loaded -- observation -> relevance -> ask]
45
- - **Proof boundaries:** [Reference `.sellable/configs/core/proof-ledger.md` and `.sellable/configs/core/wins-ledger.md` if loaded. Do not upgrade or invent claims.]
44
+ - **Outbound rules:** [Reference `~/.sellable/configs/writing/outbound.md` if loaded -- observation -> relevance -> ask]
45
+ - **Proof boundaries:** [Reference `~/.sellable/configs/core/proof-ledger.md` and `~/.sellable/configs/core/wins-ledger.md` if loaded. Do not upgrade or invent claims.]
46
46
 
47
47
  ## Do NOT Target
48
48
 
@@ -15,7 +15,7 @@ assistant message directly from the `result.result` stream-json payload —
15
15
  it does not read a file off disk.
16
16
 
17
17
  If you find yourself emitting a TodoWrite step like "Write brief.md v1
18
- to disk" or "Save brief to .sellable/..." — DELETE that step and return
18
+ to disk" or "Save brief to ~/.sellable/..." — DELETE that step and return
19
19
  the brief inline instead. The tools `Write`, `Edit`, and `Bash` are
20
20
  intentionally not in the Phase 83 harness allowlist; attempting them
21
21
  will cause a ToolSearch loop that deadlocks the turn.
@@ -37,7 +37,7 @@ offer is, why it should work, and what must be true before we launch. Do not
37
37
  prescribe message structure, opener order, or final copy here.]
38
38
 
39
39
  Draft path:
40
- `.sellable/create-campaign-brief/drafts/{workspace-slug}/{campaign-slug}/brief.md`
40
+ `~/.sellable/create-campaign-brief/drafts/{workspace-slug}/{campaign-slug}/brief.md`
41
41
 
42
42
  ## Product
43
43
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Phase 83 writes one Markdown file:
4
4
 
5
- `.sellable/create-campaign-brief/drafts/{workspace-slug}/{campaign-slug}/brief.md`
5
+ `~/.sellable/create-campaign-brief/drafts/{workspace-slug}/{campaign-slug}/brief.md`
6
6
 
7
7
  ## Rules
8
8
 
@@ -58,7 +58,7 @@ _Personalization: References their previous exit or current venture by name + th
58
58
 
59
59
  Hi {{first_name}}, let me know if i'm off, but {{seems_like_you}}.
60
60
 
61
- saw you were active in some {{signal_topic}} conversations recently and figured this might be relevant.
61
+ saw you in a few conversations around {{signal_topic}}, so hope this is relevant.
62
62
 
63
63
  we work with about 30 exited founders right now (yc, techstars, sequoia backed) handling their entire linkedin with ai + human review.
64
64
 
@@ -131,7 +131,7 @@ is this worth a look or should i send a short overview?
131
131
 
132
132
  Hi sarah, let me know if i'm off, but seems like you started building something new in the pharma space after the Benchling exit.
133
133
 
134
- saw you were active in some founder-led growth conversations recently and figured this might be relevant.
134
+ saw you in a few conversations around founder-led growth, so hope this is relevant.
135
135
 
136
136
  we work with about 30 exited founders right now (yc, techstars, sequoia backed) handling their entire linkedin with ai + human review.
137
137
 
@@ -35,70 +35,82 @@ Signal-based outreach using peer-to-peer tone. Positioning Superpower as early d
35
35
 
36
36
  **VARIANT 1 — Subject: jeff/{{first name}} intro**
37
37
 
38
- hey {{first name}}, saw you were active around some {{topic}} stuff recently and figured this might actually be relevant
38
+ hey {{first name}},
39
39
 
40
- any chance you're exploring early detection or preventive health programs at {{company}}?
40
+ saw you in a few conversations around {{topic}}, so hope this is relevant.
41
41
 
42
- we screen for 1,000+ conditions from a single blood draw and surface risks before they ever become claims.
42
+ if preventive health is anywhere near the benefits plan at {{company}}, Superpower may be worth a look.
43
43
 
44
- basically your team gets to see what's coming instead of just reacting to it
44
+ it screens for 1,000+ conditions from a single blood draw and surfaces risks before they become claims.
45
45
 
46
- can I send over some more info?
46
+ basically your team gets to see what's coming instead of only reacting to it.
47
+
48
+ should i send over the short version?
47
49
 
48
50
  **VARIANT 2 — Subject: jeff/{{first name}} intro**
49
51
 
50
- hey {{first name}}. saw you were active in some {{topic}} conversations recently and wanted to run something by you
52
+ hey {{first name}},
53
+
54
+ saw you in a few conversations around {{topic}}, so hope this is relevant.
51
55
 
52
56
  most annual physicals test 15 biomarkers max.
53
57
 
54
- there's over 100 that actually matter and the gap between those two numbers is where the expensive claims tend to sit
58
+ Superpower looks at 100+ biomarkers and screens for 1,000+ conditions from one draw.
55
59
 
56
- teams like Lyft and Notion are already exploring this. one draw, 1,000+ conditions, $199 a person.
60
+ teams like Lyft and Notion are already exploring this at $199 a person.
57
61
 
58
- if your claims costs have been going up and you're not sure where it's coming from... that gap may be a good place to start looking
62
+ if preventive health is nowhere near your lane, ignore me.
59
63
 
60
- can I send over some more info?
64
+ should i send over the short version?
61
65
 
62
66
  ## Examples
63
67
 
64
68
  **Example 1 (Variant 1 — self-insured health plans):**
65
69
  Subject: susana/prab intro
66
70
 
67
- hey susana, saw you were active around self-insured health plan content recently and figured this might actually be relevant
71
+ hey susana,
72
+
73
+ saw you in a few conversations around self-insured health plans, so hope this is relevant.
68
74
 
69
- any chance you're exploring preventive health programs at Quantum Health?
75
+ if preventive health is anywhere near the benefits plan at Quantum Health, Superpower may be worth a look.
70
76
 
71
- we screen for 1,000+ conditions from a single blood draw and surface risks before they ever become claims.
77
+ it screens for 1,000+ conditions from a single blood draw and surfaces risks before they become claims.
72
78
 
73
- basically your team gets to see what's coming instead of just reacting to it
79
+ basically your team gets to see what's coming instead of only reacting to it.
74
80
 
75
- can I send over some more info?
81
+ should i send over the short version?
76
82
 
77
83
  **Example 2 (Variant 2 — employee wellness programs):**
78
84
  Subject: lisa/prab intro
79
85
 
80
- hey lisa. saw you were active in some employee wellness programs conversations recently and wanted to run something by you
86
+ hey lisa,
87
+
88
+ saw you in a few conversations around employee wellness programs, so hope this is relevant.
81
89
 
82
90
  most annual physicals test 15 biomarkers max.
83
91
 
84
- there's over 100 that actually matter and the gap is driving the surprise expensive claims every year
92
+ Superpower looks at 100+ biomarkers and screens for 1,000+ conditions from one draw.
93
+
94
+ teams like Lyft and Notion are already exploring this at $199 a person.
85
95
 
86
- teams like Lyft and Notion are already exploring this. one test, 1,000+ conditions, $199 a person
96
+ if preventive health is nowhere near your lane, ignore me.
87
97
 
88
- can I send over some more info?
98
+ should i send over the short version?
89
99
 
90
100
  **Example 3 (Variant 1 — employee wellness programs):**
91
101
  Subject: princess/prab intro
92
102
 
93
- hey princess, saw you were active around employee wellness programs content recently and figured this might actually be relevant
103
+ hey princess,
104
+
105
+ saw you in a few conversations around employee wellness programs, so hope this is relevant.
94
106
 
95
- any chance you're exploring preventive health programs at Marriott?
107
+ if preventive health is anywhere near the benefits plan at Marriott, Superpower may be worth a look.
96
108
 
97
- we screen for 1,000+ conditions from a single blood draw and surface risks before they ever become claims.
109
+ it screens for 1,000+ conditions from a single blood draw and surfaces risks before they become claims.
98
110
 
99
- basically your team gets to see what's coming instead of just reacting to it
111
+ basically your team gets to see what's coming instead of only reacting to it.
100
112
 
101
- can I send over some more info?
113
+ should i send over the short version?
102
114
 
103
115
  ## Social Proof
104
116
 
@@ -112,7 +124,8 @@ Teams like Lyft and Notion are exploring Superpower's early detection platform.
112
124
  - **ICP filtering:** All prospects filtered against ICP criteria before entering send queue
113
125
  - **Positioning:** Early detection tool for claims prevention, not a wellness benefit
114
126
  - **Tone:** All lowercase, casual, peer-to-peer - building relationship before asking
115
- - **Two approved variants:** Testing different hooks (exploratory vs. problem-aware)
127
+ - **Two approved variants:** Testing a low-certainty signal bridge vs. proof-led
128
+ benefits mechanism
116
129
 
117
130
  ### Rubric Markdown
118
131
 
@@ -212,8 +225,8 @@ Teams like Lyft and Notion are already using early detection screening. One bloo
212
225
 
213
226
  **Subject: Prab/{{first_name}} intro**
214
227
 
215
- Hey {{first_name}}, not sure if you've looked into this but felt it may be relevant to your work.
228
+ Hey {{first_name}},
216
229
 
217
- have you ever looked into early detection or preventive health programs for {{company}}?
230
+ hope this is relevant if preventive health is anywhere near the benefits plan at {{company}}.
218
231
 
219
- we screen for 1,000+ conditions from a single blood draw and surface risks before they ever become claims.
232
+ Superpower screens for 1,000+ conditions from a single blood draw and surfaces risks before they become claims.
@@ -14,7 +14,8 @@ Included as primary gold examples:
14
14
  - `Galley`
15
15
  - `Clover`
16
16
  - `Persona`
17
- - `Superpower`
17
+ - `Superpower` — domain-language reference only; use the cleaned low-certainty
18
+ opener, not retired engagement-source phrasing
18
19
 
19
20
  Not included in runtime inspiration:
20
21
 
@@ -33,6 +34,9 @@ Not included in runtime inspiration:
33
34
 
34
35
  - Feed only endorsed examples into generation.
35
36
  - Keep bad lines only if they are explicitly labeled `BAD` and paired with a `BETTER` version.
37
+ - Treat sellable.dev, Hey Digital, Persona, Galley, and Clover as the primary
38
+ line-level quality anchors. Superpower is useful for benefits/healthcare
39
+ mechanism language, but it must not outrank those examples on opener style.
36
40
  - Default to one approved message in the generated brief unless the ICP is genuinely broad.
37
41
  - A/B CTA is optional. Use it only when the second option is truly strong.
38
42
  - If there is a great low-friction proof asset or case study, that is often the best Option B.
@@ -213,22 +217,21 @@ Why included:
213
217
 
214
218
  - simple language in a hard domain
215
219
  - useful plain-language healthcare constraint example
216
- - why it works: it asks about the buyer's existing benefits priority, explains
217
- the mechanism in plain language, and keeps the ask tiny instead of forcing a
218
- call
220
+ - why it works: it uses a low-certainty signal bridge, explains the mechanism
221
+ in plain language, and keeps the ask tiny instead of forcing a call
219
222
 
220
223
  ```md
221
224
  Hey {{first_name}},
222
225
 
223
- not sure if you've looked into this but felt it may be relevant to your work.
226
+ saw you in a few conversations around {{topic}}, so hope this is relevant.
224
227
 
225
- have you ever looked into early detection or preventive health programs for {{company}}?
228
+ if preventive health is anywhere near the benefits plan at {{company}}, Superpower may be worth a look.
226
229
 
227
- we screen for 1,000+ conditions from a single blood draw and surface risks before they ever become claims.
230
+ it screens for 1,000+ conditions from a single blood draw and surfaces risks before they become claims.
228
231
 
229
- basically your team gets to see what's coming instead of just reacting to it
232
+ basically your team gets to see what's coming instead of only reacting to it.
230
233
 
231
- can I send over some more info?
234
+ should i send over the short version?
232
235
  ```
233
236
 
234
237
  Locked production variant from the same Superpower campaign:
@@ -27,6 +27,10 @@ handoff read campaign state first: `campaignId`, `watchUrl`, `campaignBrief`,
27
27
  `leadScoringRubrics`, `approvedMessageTemplate`, `senderIds`,
28
28
  `sequenceTemplate`, and running state. Local draft files are debug-only.
29
29
 
30
+ There is no normal approval-packet, commit-gate, or atomic-mint path in the
31
+ active flow. Legacy packet/mint artifacts stay in
32
+ `create-campaign-v2-validation` and rehearsal material only.
33
+
30
34
  ## Normal Flow
31
35
 
32
36
  1. Bootstrap and tell the user the active Sellable workspace.
@@ -47,12 +47,13 @@ recite profile facts. `"I noticed your..."` reads as scraped intel.
47
47
  **Allowed alternative:** Use a concise permissioned bridge:
48
48
  `"Hope this is relevant if X is still live."`, `"Saw you might be
49
49
  interested in X, so hope this is relevant."`, `"Saw you in a few
50
- conversations around X, so hope this is relevant."` for LinkedIn-post-sourced
51
- campaigns, or the self-aware
52
- `"saw you raise your hand for X, so figured this was (hopefully) worth
53
- sending"` or `"saw you raise your hand for X (creepy to reach out based
54
- on that, i know) - but this felt too on the nose to ignore"` shapes when the
55
- engagement source is the reason for the note.
50
+ conversations around X, so hope this is relevant."`, or `"Found you in a
51
+ thread about X, so may be off, but this seemed relevant."` for
52
+ LinkedIn-post-sourced campaigns. Use the self-aware `"saw you raise your
53
+ hand for X, so figured this was (hopefully) worth sending"` or `"saw you
54
+ raise your hand for X (creepy to reach out based on that, i know) - but
55
+ this felt too on the nose to ignore"` shapes only when the source was an
56
+ explicit lead-magnet comment, reply, or opt-in.
56
57
 
57
58
  **Severity:** REJECT
58
59
 
@@ -277,13 +278,25 @@ creating relevance. The message sounds like a lead scraper explaining
277
278
  why it picked the recipient, then asking the recipient to forgive the
278
279
  reach-out.
279
280
 
280
- **Allowed alternative:** Use a concise topic-level bridge when the
281
- source is meaningful, then continue with apologetic uncertainty:
282
- `"Saw you in a few conversations about LinkedIn outreach, so may be
283
- off, but this seemed relevant."` or `"Saw you in a few conversations
284
- around LinkedIn outreach, so hope this is relevant."` If the source was
285
- only casual reading or the role/topic connection is weak, omit the
286
- personalization line and open from the buyer pain.
281
+ **Allowed alternative:** If the source is the sender's own LinkedIn post and
282
+ row data proves a reaction/comment, a light first-person acknowledgment can be
283
+ natural: `"appreciate you showing some love on my post about LinkedIn
284
+ outreach"` or `"thanks for showing support on my LinkedIn outreach post."`
285
+ Do not name a comment unless comment text is present. Follow the acknowledgment
286
+ with a soft relevance bridge before broad pain or product copy, for example:
287
+ `"figured this might be relevant if LinkedIn is becoming more of a GTM channel
288
+ for Acme."` The next line must then connect to that same channel/workflow,
289
+ not pivot into a generic pain claim. If the sequence reads like
290
+ `thanks for the post support` -> `anyway, most teams...`, it is an AI tell
291
+ because the lines are adjacent but not connected. For third-party post
292
+ sources, use a concise topic-level bridge when the source is meaningful, then
293
+ continue with apologetic uncertainty: `"Saw you in a few conversations about
294
+ LinkedIn outreach, so may be off, but this seemed relevant."` or `"Saw you in
295
+ a few conversations around LinkedIn outreach, so hope this is relevant."`
296
+ `"Found you in a thread about LinkedIn outreach, so may be off, but this seemed
297
+ relevant."` is allowed only when it stays topic-level and does not explain
298
+ sourcing mechanics. If the source was only casual reading or the role/topic
299
+ connection is weak, omit the personalization line and open from the buyer pain.
287
300
 
288
301
  **Severity:** REJECT
289
302
 
@@ -298,13 +311,35 @@ claim the recipient did not make. The line tells the buyer about
298
311
  themselves and assumes the workflow belongs to them.
299
312
 
300
313
  **Allowed alternative:** Keep the apologetic uncertainty without
301
- asserting fit: `"May be off, but if outbound is anywhere near your
302
- lane, this might be useful."` A low-pressure PS such as `"p.s. if this
303
- is nowhere near your outbound workflow, ignore me"` is allowed when it
314
+ asserting fit: `"May be off, but if outbound is relevant to what you're
315
+ working on, this might be useful."` A low-pressure PS such as `"p.s. if this
316
+ is not relevant to your outbound workflow, ignore me"` is allowed when it
304
317
  does not narrate the source.
305
318
 
306
319
  **Severity:** REJECT
307
320
 
321
+ ## Tell #17 — Flattened "worth sending" source bridge
322
+
323
+ **Pattern:** `"saw you raise your hand for [topic], so figured this was
324
+ worth sending"` / `"figured this was worth sending"` without the
325
+ parenthetical uncertainty `(hopefully)` or a `hope this is relevant`
326
+ bridge.
327
+
328
+ **Why it's an AI tell:** It sounds like a model trying to justify the
329
+ outreach after reading a signal. The flat version makes the sender sound
330
+ over-certain and self-focused: "I decided this was worth sending." Real
331
+ operators usually soften the bridge or make it explicitly tentative.
332
+
333
+ **Allowed alternative:** Use a permissioned, lower-certainty bridge:
334
+ `"saw you raise your hand for [topic], so figured this was (hopefully)
335
+ worth sending."` only for explicit lead-magnet comments, replies, or
336
+ opt-ins. Otherwise use `"saw you might be interested in [topic], so hope
337
+ this is relevant."`, `"saw you in a few conversations around [topic], so
338
+ hope this is relevant."`, or `"found you in a thread about [topic], so
339
+ may be off, but this seemed relevant."`
340
+
341
+ **Severity:** REJECT
342
+
308
343
  ---
309
344
 
310
345
  ## How to add new tells
@@ -413,7 +413,7 @@ queue, attach sequence, or start. If a draft shell exists, leave it paused/
413
413
  non-sendable for operator cleanup instead of silently deleting a workspace row.
414
414
 
415
415
  Draft effect: move the draft directory to
416
- `.sellable/create-campaign-v2/drafts/{workspace-slug}/.aborted/{campaign-slug}-{timestamp}/`.
416
+ `~/.sellable/create-campaign-v2/drafts/{workspace-slug}/.aborted/{campaign-slug}-{timestamp}/`.
417
417
  Legacy no-shell runs touch no DB rows and create no `CampaignOffer`.
418
418
  No DB rows touched in legacy no-shell aborts; draft-shell aborts leave the
419
419
  non-sendable shell for operator cleanup.