@sellable/install 0.1.211 → 0.1.212

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.
@@ -72,8 +72,9 @@ const CODEX_PLUGIN_COMPAT_VERSIONS = [
72
72
  "0.1.40",
73
73
  "0.1.41",
74
74
  ];
75
- const INSTALL_PACKAGE_SPEC =
75
+ const RAW_INSTALL_PACKAGE_SPEC =
76
76
  process.env.SELLABLE_INSTALL_PACKAGE_SPEC || "@sellable/install@latest";
77
+ const INSTALL_PACKAGE_SPEC = normalizeWindowsPackageSpec(RAW_INSTALL_PACKAGE_SPEC);
77
78
 
78
79
  const useColor = Boolean(output.isTTY) && process.env.NO_COLOR === undefined;
79
80
  const C = {
@@ -89,6 +90,15 @@ const C = {
89
90
 
90
91
  let VERBOSE = false;
91
92
 
93
+ function normalizeWindowsPackageSpec(value) {
94
+ if (typeof value !== "string") return value;
95
+ if (/^[A-Za-z]:\//.test(value)) return value.replace(/\//g, "\\");
96
+ if (/^\/[A-Za-z]\//.test(value)) {
97
+ return `${value[1]}:${value.slice(2)}`.replace(/\//g, "\\");
98
+ }
99
+ return value;
100
+ }
101
+
92
102
  function logVerbose(line) {
93
103
  if (VERBOSE) console.log(line);
94
104
  }
@@ -263,7 +273,7 @@ function parseArgs(argv) {
263
273
  } else if (arg === "--api-url") {
264
274
  opts.apiUrl = next();
265
275
  } else if (arg === "--mcp-package") {
266
- opts.mcpPackage = next();
276
+ opts.mcpPackage = normalizeWindowsPackageSpec(next());
267
277
  } else if (arg === "--local-command") {
268
278
  opts.localCommand = next();
269
279
  } else if (arg === "--hosted-url") {
@@ -771,46 +781,54 @@ function codexSkillOpenAiYaml(displayName, description) {
771
781
  `;
772
782
  }
773
783
 
774
- function createCampaignHostContract(host) {
784
+ function installedHostContract(host, commandName) {
775
785
  if (host === "codex") {
776
786
  return `## Installed Host Contract
777
787
 
778
- This installed skill is running in Codex. Treat Codex as the current host, use
779
- \`request_user_input\` for structured questions when it is exposed, use
780
- \`$sellable:create-campaign\` in user-facing retry instructions, and call
781
- \`mcp__sellable__bootstrap_create_campaign\` with \`host: "Codex"\` plus the
782
- current Codex model and reasoning when available.
788
+ This installed skill is running in Codex. When the shared workflow body or
789
+ fallback text mentions both Claude Code and Codex for internal parity, choose
790
+ the Codex instruction for customer-facing language and host functions.
783
791
 
784
- Do not describe this run as Claude Code and do not recommend Claude Code-only
785
- commands or settings from this Codex skill.`;
786
- }
792
+ - Customer-facing command: \`$sellable:${commandName}\`
793
+ - Structured question function: \`request_user_input\`
794
+ - Bootstrap host label: \`host: "Codex"\`
795
+ - Install/reload blocker label: Codex install/reload problem
796
+ - Reload instruction: fully quit and reopen Codex Desktop, then start a new thread
787
797
 
798
+ Do not tell Codex users to run \`/sellable:${commandName}\`, use
799
+ \`AskUserQuestion\`, or restart Claude Code. Do not describe this run as Claude Code.`;
800
+ }
788
801
  if (host === "claude") {
789
802
  return `## Installed Host Contract
790
803
 
791
- This installed command is running in Claude Code. Treat Claude Code as the
792
- current host, use \`AskUserQuestion\` for structured questions, use
793
- \`/sellable:create-campaign\` in user-facing retry instructions, and call
794
- \`mcp__sellable__bootstrap_create_campaign\` with \`host: "Claude Code"\` plus
795
- the current Claude Code model and reasoning when available.
804
+ This installed command is running in Claude Code. When the shared workflow body
805
+ or fallback text mentions both Claude Code and Codex for internal parity, choose
806
+ the Claude Code instruction for customer-facing language and host functions.
796
807
 
797
- Do not describe this run as Codex and do not recommend Codex-only commands or
798
- settings from this Claude Code command.`;
799
- }
808
+ - Customer-facing command: \`/sellable:${commandName}\`
809
+ - Structured question function: \`AskUserQuestion\`
810
+ - Bootstrap host label: \`host: "Claude Code"\`
811
+ - Install/reload blocker label: Claude Code install/reload problem
812
+ - Reload instruction: fully quit and reopen Claude Code, then start a new session
800
813
 
814
+ Do not tell Claude Code users to run \`$sellable:${commandName}\`, use
815
+ \`request_user_input\`, or restart Codex Desktop. Do not describe this run as Codex.`;
816
+ }
801
817
  return "";
802
818
  }
803
819
 
804
- function addCreateCampaignHostContract(markdown, host) {
805
- const contract = createCampaignHostContract(host);
806
- if (!contract) return markdown;
820
+ function stampInstalledHost(markdown, host, commandName) {
821
+ const preamble = installedHostContract(host, commandName);
822
+ if (!preamble || markdown.includes("## Installed Host Contract")) {
823
+ return markdown;
824
+ }
807
825
  return String(markdown).replace(
808
- "\n# Sellable Create Campaign\n",
809
- `\n# Sellable Create Campaign\n\n${contract}\n`
826
+ /(^# .+\n\n)/m,
827
+ `$1${preamble}\n\n`
810
828
  );
811
829
  }
812
830
 
813
- function createCampaignSkillMd({ host = "shared" } = {}) {
831
+ function createCampaignSkillMd(host = "shared") {
814
832
  // Single source of truth: ../skill-templates/create-campaign.md, which is
815
833
  // copied from the canonical mcp/sellable/skills/create-campaign/SKILL.md at
816
834
  // publish time via scripts/sync-skill-templates.mjs (prepublishOnly hook).
@@ -825,15 +843,16 @@ function createCampaignSkillMd({ host = "shared" } = {}) {
825
843
  "create-campaign.md"
826
844
  );
827
845
  if (existsSync(templatePath)) {
828
- return addCreateCampaignHostContract(
846
+ return stampInstalledHost(
829
847
  readFileSync(templatePath, "utf8"),
830
- host
848
+ host,
849
+ "create-campaign"
831
850
  );
832
851
  }
833
852
  } catch {
834
853
  // fall through to hardcoded fallback below
835
854
  }
836
- return `---
855
+ return stampInstalledHost(`---
837
856
  name: create-campaign
838
857
  description: Create a Sellable campaign through the approval-gated workflow.
839
858
  allowed-tools:
@@ -856,17 +875,11 @@ person/company this campaign is for, then I’ll turn that into a campaign brief
856
875
  before anything is created.
857
876
  \`\`\`
858
877
 
859
- Exception: if \`bootstrap_create_campaign.modelQuality.status === "warn"\` and
860
- \`bootstrap_create_campaign.modelQuality.metadataStale !== true\`, the first
861
- visible campaign message must be the model-quality warning from
862
- \`modelQuality.message\`. Ask the user to switch to the configured minimum model
863
- or explicitly continue anyway before identity setup, research, lead filtering,
864
- message generation, or launch review. If \`metadataStale === true\`, continue
865
- normally and do not ask the user to switch.
866
-
867
- If \`bootstrap_create_campaign.modelQuality.metadataStale === true\`, continue
868
- normally. Do not ask the user to switch models; this is an accepted Codex host
869
- metadata mismatch.
878
+ Exception: if \`bootstrap_create_campaign.modelQuality.status === "warn"\`, the
879
+ first visible campaign message must be the model-quality warning from
880
+ \`modelQuality.message\`. Only trust that warning when bootstrap received active
881
+ turn/runtime metadata or an explicit user-confirmed model. Do not warn from
882
+ config defaults, stale host labels, or inferred model names.
870
883
 
871
884
  If a linked/local skill file is stale or missing, silently use the installed
872
885
  \`sellable@sellable\` plugin copy. Do not tell the user about the stale link,
@@ -884,6 +897,56 @@ clear business decisions, tradeoffs, and approval gates. Use product language:
884
897
  - "I can create a draft shell for you to watch with approval gates before
885
898
  sourcing", not mutation jargon
886
899
 
900
+ ## Active Model Metadata
901
+
902
+ Before calling \`bootstrap_create_campaign\`, collect the active host model data
903
+ only from a source that can describe this turn:
904
+
905
+ - Codex: if \`mcp__node_repl__js\` is available, inspect only
906
+ \`nodeRepl.requestMeta["x-codex-turn-metadata"].model\` and
907
+ \`nodeRepl.requestMeta["x-codex-turn-metadata"].reasoning_effort\`. Pass those
908
+ values as \`model\` and \`reasoningEffort\`, with
909
+ \`modelMetadataSource: "codex_turn_metadata"\`.
910
+ - Codex fallback/cross-check: if active turn metadata is unavailable, you may
911
+ inspect \`~/.codex/config.toml\` for \`model\` and
912
+ \`model_reasoning_effort\`, but pass
913
+ \`modelMetadataSource: "codex_config_fallback"\` and do not treat it as a
914
+ reason to ask the user to switch models. Active turn metadata wins if it
915
+ differs from config.
916
+ - Claude Code / Opus: use active Claude runtime metadata only if the current
917
+ host exposes model and effort for this same session, with
918
+ \`modelMetadataSource: "claude_runtime_metadata"\`. Current Claude Code MCP
919
+ tool calls may not include model or effort metadata; when they do not, omit
920
+ \`model\`, \`reasoningEffort\`, and \`modelMetadataSource\`.
921
+ - Claude Code session-context self-report: if your current Claude session
922
+ context explicitly states both the exact model ID and effort/thinking level,
923
+ report it internally in this shape and pass it to bootstrap with
924
+ \`modelMetadataSource: "claude_session_context"\`:
925
+
926
+ \`\`\`text
927
+ - Model (name): ...
928
+ - Model (ID): ...
929
+ - Reasoning effort: ...
930
+ - Source: active Claude Code session context
931
+ \`\`\`
932
+
933
+ Use this only when the values are explicitly present in the current session
934
+ context. Do not infer an ID from the friendly name, do not infer effort from
935
+ \`alwaysThinkingEnabled\`, and do not show this self-report to the user during
936
+ normal campaign setup.
937
+ - Do not run a nested \`claude -p\`, inspect \`~/.claude/settings.json\`, or read
938
+ Claude CLI defaults as proof of the user's active Claude Code session. Those
939
+ checks can validate a new child session or saved defaults, but not this
940
+ session's actual model and effort.
941
+ - If the user explicitly provides active Claude \`/status\` or \`/model\` output
942
+ that includes both model and effort, pass it with
943
+ \`modelMetadataSource: "user_confirmed"\`. If it is missing either model or
944
+ effort, treat the metadata as unknown and continue.
945
+
946
+ Never invent the model or reasoning effort. Never pass config defaults as active
947
+ metadata. If bootstrap returns \`modelQuality.status === "unknown"\`, continue
948
+ without asking the user to switch models.
949
+
887
950
  When explaining source decisions, show the concrete counts behind the
888
951
  logic: lanes searched, timeframe, raw result counts, finalist posts or preview
889
952
  rows, sampled people, sampled fits as n/N (%), estimated usable people, and the
@@ -1305,13 +1368,19 @@ updates.
1305
1368
  - Do not call \`mcp__sellable__get_campaigns\`.
1306
1369
  - Do not call \`mcp__sellable__get_campaign\` to hunt for IDs.
1307
1370
  - Do not call \`mcp__sellable__create_campaign({ campaignId: ... })\` unless the user supplied that id.
1308
- 5. Call \`mcp__sellable__bootstrap_create_campaign({ flowVersion: "v2", campaignId?, host?, model?, reasoningEffort? })\`.
1309
- Pass the current host, model, and reasoning when the host exposes them.
1371
+ 5. Call \`mcp__sellable__bootstrap_create_campaign({ flowVersion: "v2", campaignId?, host?, model?, reasoningEffort?, modelMetadataSource? })\`.
1372
+ Pass model metadata only when collected by the Active Model Metadata rules
1373
+ above. For Codex active turn metadata, pass
1374
+ \`modelMetadataSource: "codex_turn_metadata"\`. For explicit Claude session
1375
+ context, pass \`modelMetadataSource: "claude_session_context"\`. For explicit
1376
+ user-confirmed Claude \`/status\` or \`/model\` output, pass
1377
+ \`modelMetadataSource: "user_confirmed"\` only when it includes both model and
1378
+ effort.
1310
1379
  6. If \`safeToProceed !== true\`, stop and show \`blockingErrors\` + \`nextStep\`.
1311
- 7. If \`modelQuality.status === "warn"\` and \`modelQuality.metadataStale !== true\`,
1312
- show \`modelQuality.message\` before any setup/research and wait for the user
1313
- to switch or explicitly continue. If \`metadataStale === true\`, continue
1314
- normally and do not tell the user to switch.
1380
+ 7. If \`modelQuality.status === "warn"\`, show \`modelQuality.message\` before
1381
+ any setup/research and wait for the user to switch or explicitly continue. If
1382
+ \`modelQuality.status === "unknown"\`, continue; do not tell the user to
1383
+ switch models.
1315
1384
 
1316
1385
  ## Execute Workflow
1317
1386
 
@@ -1392,10 +1461,10 @@ updates.
1392
1461
  If subskill lookup fails, use
1393
1462
  \`mcp__sellable__search_subskill_prompts({ query: "create-campaign-v2" })\`,
1394
1463
  then retry \`get_subskill_prompt\`.
1395
- `;
1464
+ `, host, "create-campaign");
1396
1465
  }
1397
1466
 
1398
- function createAbTestSkillMd() {
1467
+ function createAbTestSkillMd(host = "shared") {
1399
1468
  try {
1400
1469
  const here = dirname(fileURLToPath(import.meta.url));
1401
1470
  const templatePath = join(
@@ -1405,12 +1474,16 @@ function createAbTestSkillMd() {
1405
1474
  "create-ab-test.md"
1406
1475
  );
1407
1476
  if (existsSync(templatePath)) {
1408
- return readFileSync(templatePath, "utf8");
1477
+ return stampInstalledHost(
1478
+ readFileSync(templatePath, "utf8"),
1479
+ host,
1480
+ "create-ab-test"
1481
+ );
1409
1482
  }
1410
1483
  } catch {
1411
1484
  // fall through to hardcoded fallback below
1412
1485
  }
1413
- return `---
1486
+ return stampInstalledHost(`---
1414
1487
  name: create-ab-test
1415
1488
  description: Create a Sellable campaign A/B test from a clean source lead list.
1416
1489
  visibility: public
@@ -1426,11 +1499,11 @@ allowed-tools:
1426
1499
  # Sellable Create A/B Test
1427
1500
 
1428
1501
  Use \`prepare_campaign_ab_test\` to create clean A/B split lead lists and review-copy campaigns. Do not call \`export_table_csv\` from generated campaign workflow tables as lead source data, and do not call \`start_campaign\`.
1429
- `;
1502
+ `, host, "create-ab-test");
1430
1503
  }
1431
1504
 
1432
- function genericSellableSkillMd({ name, title, description }) {
1433
- return `---
1505
+ function genericSellableSkillMd({ name, title, description, host = "shared" }) {
1506
+ return stampInstalledHost(`---
1434
1507
  name: ${name}
1435
1508
  description: ${yamlString(description)}
1436
1509
  allowed-tools:
@@ -1465,11 +1538,11 @@ Desktop, then start a new thread.
1465
1538
  ## MCP Prompt Fallback
1466
1539
 
1467
1540
  If subskill lookup fails, use \`mcp__sellable__search_subskill_prompts({ query: "${name}" })\`, then retry \`get_subskill_prompt\`.
1468
- `;
1541
+ `, host, name);
1469
1542
  }
1470
1543
 
1471
- function foundationSkillMd() {
1472
- return `---
1544
+ function foundationSkillMd(host = "shared") {
1545
+ return stampInstalledHost(`---
1473
1546
  name: foundation
1474
1547
  description: ${yamlString(FOUNDATION_SKILL_DESCRIPTION)}
1475
1548
  allowed-tools:
@@ -1528,11 +1601,11 @@ Desktop, then start a new thread.
1528
1601
  If exact subskill lookup fails, use
1529
1602
  \`mcp__sellable__search_subskill_prompts({ query: "foundation", includePublic: true, includeInternal: true })\`,
1530
1603
  then retry \`get_subskill_prompt\`.
1531
- `;
1604
+ `, host, "foundation");
1532
1605
  }
1533
1606
 
1534
- function contentSkillMd() {
1535
- return `---
1607
+ function contentSkillMd(host = "shared") {
1608
+ return stampInstalledHost(`---
1536
1609
  name: content
1537
1610
  description: Add transcripts and rough ideas, cluster recurring themes, ideate post seeds, and hand draft requests to create-post.
1538
1611
  allowed-tools:
@@ -1598,11 +1671,11 @@ Desktop, then start a new thread.
1598
1671
  If exact subskill lookup fails, use
1599
1672
  \`mcp__sellable__search_subskill_prompts({ query: "content", includePublic: true, includeInternal: true })\`,
1600
1673
  then retry \`get_subskill_prompt\`.
1601
- `;
1674
+ `, host, "content");
1602
1675
  }
1603
1676
 
1604
- function createPostSkillMd() {
1605
- return `---
1677
+ function createPostSkillMd(host = "shared") {
1678
+ return stampInstalledHost(`---
1606
1679
  name: create-post
1607
1680
  description: Capture rough LinkedIn post ideas, develop a valuable premise, research current hooks and audience tension, then save validated drafts in the user's voice.
1608
1681
  allowed-tools:
@@ -1672,7 +1745,7 @@ Desktop, then start a new thread.
1672
1745
  If exact subskill lookup fails, use
1673
1746
  \`mcp__sellable__search_subskill_prompts({ query: "create-post", includePublic: true, includeInternal: true })\`,
1674
1747
  then retry \`get_subskill_prompt\`.
1675
- `;
1748
+ `, host, "create-post");
1676
1749
  }
1677
1750
 
1678
1751
  function createCampaignSoulMd() {
@@ -1869,7 +1942,7 @@ function codexPluginSkills() {
1869
1942
  dir: "sellable-create-campaign",
1870
1943
  displayName: "Sellable Create Campaign",
1871
1944
  description: "Create a Sellable campaign with approval gates",
1872
- skillMd: createCampaignSkillMd({ host: "codex" }),
1945
+ skillMd: createCampaignSkillMd("codex"),
1873
1946
  soulMd: createCampaignSoulMd(),
1874
1947
  },
1875
1948
  {
@@ -2093,7 +2166,7 @@ function claudeCommands() {
2093
2166
  filename: join("sellable", "create-campaign.md"),
2094
2167
  description: "Create a Sellable campaign through the approval-gated workflow.",
2095
2168
  argumentHint: "[campaign goal, company, or offer]",
2096
- skillMd: createCampaignSkillMd({ host: "claude" }),
2169
+ skillMd: createCampaignSkillMd("claude"),
2097
2170
  allowedTools: ["AskUserQuestion", "Task", ...CREATE_CAMPAIGN_ALLOWED_TOOLS],
2098
2171
  },
2099
2172
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/install",
3
- "version": "0.1.211",
3
+ "version": "0.1.212",
4
4
  "type": "module",
5
5
  "description": "One-command installer for Sellable MCP in Claude Code and Codex",
6
6
  "bin": {
@@ -179,17 +179,11 @@ person/company this campaign is for, then I’ll turn that into a campaign brief
179
179
  before we move into lead sourcing.
180
180
  ```
181
181
 
182
- Exception: if `bootstrap_create_campaign.modelQuality.status === "warn"` and
183
- `bootstrap_create_campaign.modelQuality.metadataStale !== true`, the first
184
- visible campaign message must be the model-quality warning from
185
- `modelQuality.message`. Ask the user to switch to the configured minimum model
186
- or explicitly continue anyway before identity setup, research, lead filtering,
187
- message generation, or launch review. If `metadataStale === true`, continue
188
- normally and do not ask the user to switch.
189
-
190
- If `bootstrap_create_campaign.modelQuality.metadataStale === true`, continue
191
- normally. Do not ask the user to switch models; this is an accepted Codex host
192
- metadata mismatch.
182
+ Exception: if `bootstrap_create_campaign.modelQuality.status === "warn"`, the
183
+ first visible campaign message must be the model-quality warning from
184
+ `modelQuality.message`. Only trust that warning when bootstrap received active
185
+ turn/runtime metadata or an explicit user-confirmed model. Do not warn from
186
+ config defaults, stale host labels, or inferred model names.
193
187
 
194
188
  If a linked/local skill file is stale or missing, silently use the installed
195
189
  `sellable@sellable` plugin copy. Do not tell the user about the stale link,
@@ -207,6 +201,55 @@ clear business decisions, tradeoffs, and approval gates. Use product language:
207
201
  - "I can create a draft shell for you to watch with approval gates before
208
202
  sourcing", not mutation jargon
209
203
 
204
+ ## Active Model Metadata
205
+
206
+ Before calling `bootstrap_create_campaign`, collect the active host model data
207
+ only from a source that can describe this turn:
208
+
209
+ - Codex: if `mcp__node_repl__js` is available, inspect only
210
+ `nodeRepl.requestMeta["x-codex-turn-metadata"].model` and
211
+ `nodeRepl.requestMeta["x-codex-turn-metadata"].reasoning_effort`. Pass those
212
+ values as `model` and `reasoningEffort`, with
213
+ `modelMetadataSource: "codex_turn_metadata"`.
214
+ - Codex fallback/cross-check: if active turn metadata is unavailable, you may
215
+ inspect `~/.codex/config.toml` for `model` and `model_reasoning_effort`, but
216
+ pass `modelMetadataSource: "codex_config_fallback"` and do not treat it as a
217
+ reason to ask the user to switch models. Active turn metadata wins if it
218
+ differs from config.
219
+ - Claude Code / Opus: use active Claude runtime metadata only if the current
220
+ host exposes model and effort for this same session, with
221
+ `modelMetadataSource: "claude_runtime_metadata"`. Current Claude Code MCP
222
+ tool calls may not include model or effort metadata; when they do not, omit
223
+ `model`, `reasoningEffort`, and `modelMetadataSource`.
224
+ - Claude Code session-context self-report: if your current Claude session
225
+ context explicitly states both the exact model ID and effort/thinking level,
226
+ report it internally in this shape and pass it to bootstrap with
227
+ `modelMetadataSource: "claude_session_context"`:
228
+
229
+ ```text
230
+ - Model (name): ...
231
+ - Model (ID): ...
232
+ - Reasoning effort: ...
233
+ - Source: active Claude Code session context
234
+ ```
235
+
236
+ Use this only when the values are explicitly present in the current session
237
+ context. Do not infer an ID from the friendly name, do not infer effort from
238
+ `alwaysThinkingEnabled`, and do not show this self-report to the user during
239
+ normal campaign setup.
240
+ - Do not run a nested `claude -p`, inspect `~/.claude/settings.json`, or read
241
+ Claude CLI defaults as proof of the user's active Claude Code session. Those
242
+ checks can validate a new child session or saved defaults, but not this
243
+ session's actual model and effort.
244
+ - If the user explicitly provides active Claude `/status` or `/model` output
245
+ that includes both model and effort, pass it with
246
+ `modelMetadataSource: "user_confirmed"`. If it is missing either model or
247
+ effort, treat the metadata as unknown and continue.
248
+
249
+ Never invent the model or reasoning effort. Never pass config defaults as active
250
+ metadata. If bootstrap returns `modelQuality.status === "unknown"`, continue
251
+ without asking the user to switch models.
252
+
210
253
  Approval and safety copy should be tasteful. State what the current approval
211
254
  covers once, in one short sentence, then move on. Do not append repeated
212
255
  "nothing starts / no leads import / no sending" disclaimers to routine progress
@@ -775,10 +818,9 @@ messages, and wait for final launch approval.
775
818
  What's your LinkedIn profile URL or handle?
776
819
  ```
777
820
 
778
- Codex only: do not silently ask intake or approval questions as plain chat when
779
- `request_user_input` is unavailable in an interactive Codex session. Claude Code
780
- uses `AskUserQuestion`; do not apply this Codex setup blocker in Claude Code.
781
- In Codex, stop and tell the user:
821
+ Do not silently ask Codex intake or approval questions as plain chat when
822
+ `request_user_input` is unavailable in an interactive session. Stop and tell
823
+ the user:
782
824
 
783
825
  ```text
784
826
  I need Codex’s quick question panel to collect campaign inputs and approvals cleanly.
@@ -817,18 +859,17 @@ there.
817
859
  ## Bootstrap
818
860
 
819
861
  MCP tool access is required. First call `mcp__sellable__get_auth_status({})`
820
- directly. If that tool is unavailable, stop and say this is a Sellable
821
- install/reload problem for the current host, not a campaign problem. Tell the
822
- user to run `curl -fsSL "https://app.sellable.dev/api/v2/cli/install" | sh` so
823
- the packaged MCP server and the current host integration are installed. If they
824
- want an agent-readable checklist, tell them:
862
+ directly. If that tool is unavailable, stop and say this is a Codex
863
+ install/reload problem, not a campaign problem. Tell the user to
864
+ run `curl -fsSL "https://app.sellable.dev/api/v2/cli/install" | sh` so the
865
+ packaged MCP server, Codex Desktop plugin, and Sellable skill bundle are
866
+ installed. If they want an agent-readable checklist, tell them:
825
867
  `Install Sellable CLI and skills using https://app.sellable.dev/agent-install.txt`.
826
868
  For CLI verification, tell them to run
827
869
  `sellable --verify-only --host all --json --artifact "$HOME/.local/sellable/app-sellable-dev/installer/.last-verify.json"`.
828
- After that, they must fully quit and reopen the current host app before starting
829
- a new thread. In Codex, say Codex Desktop. In Claude Code, say Claude Code. Do
830
- not use `scripts/mcp/sellable-tool-call.mjs`, `npm run`, `node`, or any local
831
- harness as a fallback for this interactive skill.
870
+ After that, they must fully quit and reopen Codex Desktop before starting a new
871
+ thread. Do not use `scripts/mcp/sellable-tool-call.mjs`, `npm run`, `node`, or
872
+ any local harness as a fallback for this interactive skill.
832
873
  Do not mention prompt loading, local skill files, missing linked versions,
833
874
  plugin cache paths, MCP namespaces, or runbooks in customer-facing progress
834
875
  updates.
@@ -940,15 +981,19 @@ updates.
940
981
  - Do not call `mcp__sellable__get_campaigns`.
941
982
  - Do not call `mcp__sellable__get_campaign` to hunt for IDs.
942
983
  - Do not call `mcp__sellable__create_campaign({ campaignId: ... })` unless the user supplied that id.
943
- 6. Call `mcp__sellable__bootstrap_create_campaign({ flowVersion: "v2", campaignId?, host, model?, reasoningEffort? })`.
944
- Pass the explicit current host label: `host: "Codex"` from Codex and
945
- `host: "Claude Code"` from Claude Code. Also pass the current model and
946
- reasoning when the host exposes them.
984
+ 6. Call `mcp__sellable__bootstrap_create_campaign({ flowVersion: "v2", campaignId?, host?, model?, reasoningEffort?, modelMetadataSource? })`.
985
+ Pass model metadata only when collected by the Active Model Metadata rules
986
+ above. For Codex active turn metadata, pass
987
+ `modelMetadataSource: "codex_turn_metadata"`. For explicit Claude session
988
+ context, pass `modelMetadataSource: "claude_session_context"`. For explicit
989
+ user-confirmed Claude `/status` or `/model` output, pass
990
+ `modelMetadataSource: "user_confirmed"` only when it includes both model and
991
+ effort.
947
992
  7. If `safeToProceed !== true`, stop and show `blockingErrors` + `nextStep`.
948
- 8. If `modelQuality.status === "warn"` and `modelQuality.metadataStale !== true`,
949
- show `modelQuality.message` before any setup/research and wait for the user
950
- to switch or explicitly continue. If `metadataStale === true`, continue
951
- normally and do not tell the user to switch.
993
+ 8. If `modelQuality.status === "warn"`, show `modelQuality.message` before any
994
+ setup/research and wait for the user to switch or explicitly continue. If
995
+ `modelQuality.status === "unknown"`, continue; do not tell the user to
996
+ switch models.
952
997
 
953
998
  ## Execute Workflow
954
999