@sellable/mcp 0.1.314 → 0.1.318
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 +25 -4
- package/dist/tools/bootstrap.d.ts +5 -0
- package/dist/tools/bootstrap.js +10 -5
- package/dist/tools/model-quality.d.ts +3 -2
- package/dist/tools/model-quality.js +47 -113
- package/dist/tools/registry.d.ts +4 -0
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +66 -17
- package/skills/create-campaign/core/model-quality.json +4 -5
- package/skills/create-campaign-v2/references/approval-gate-framing.md +6 -1
package/README.md
CHANGED
|
@@ -302,11 +302,32 @@ Use the same MCP runtime preflight in both hosts:
|
|
|
302
302
|
|
|
303
303
|
Canonical shortcut:
|
|
304
304
|
|
|
305
|
-
- `bootstrap_create_campaign({ flowVersion: "v2", campaignId?, host?, model?, reasoningEffort? })`
|
|
305
|
+
- `bootstrap_create_campaign({ flowVersion: "v2", campaignId?, host?, model?, reasoningEffort?, modelMetadataSource? })`
|
|
306
|
+
|
|
307
|
+
Pass model/reasoning metadata only when it comes from active turn/runtime
|
|
308
|
+
metadata or explicit user confirmation. For Codex, use
|
|
309
|
+
`nodeRepl.requestMeta["x-codex-turn-metadata"]` and pass
|
|
310
|
+
`modelMetadataSource: "codex_turn_metadata"`. Config files such as
|
|
311
|
+
`~/.codex/config.toml` are fallback/cross-check evidence only and must not
|
|
312
|
+
trigger model-switch warnings.
|
|
313
|
+
|
|
314
|
+
For Claude Code, pass model metadata only when the current host exposes active
|
|
315
|
+
runtime model and effort for the same session, or when the user explicitly
|
|
316
|
+
confirms current `/status` or `/model` output that includes both model and effort.
|
|
317
|
+
If the current Claude session context explicitly states both values, use
|
|
318
|
+
`modelMetadataSource: "claude_session_context"`. Use
|
|
319
|
+
`modelMetadataSource: "user_confirmed"` for explicit user confirmation. Do not
|
|
320
|
+
use a nested `claude -p` run, `~/.claude/settings.json`, or CLI defaults as
|
|
321
|
+
active-session evidence.
|
|
322
|
+
|
|
323
|
+
Claude session-context self-report shape:
|
|
306
324
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
325
|
+
```text
|
|
326
|
+
- Model (name): ...
|
|
327
|
+
- Model (ID): ...
|
|
328
|
+
- Reasoning effort: ...
|
|
329
|
+
- Source: active Claude Code session context
|
|
330
|
+
```
|
|
310
331
|
|
|
311
332
|
If bootstrap returns blocking errors, fail fast and do not continue into provider
|
|
312
333
|
search/import tools.
|
|
@@ -11,6 +11,7 @@ type BootstrapCreateCampaignInput = {
|
|
|
11
11
|
host?: string;
|
|
12
12
|
model?: string;
|
|
13
13
|
reasoningEffort?: string;
|
|
14
|
+
modelMetadataSource?: string;
|
|
14
15
|
};
|
|
15
16
|
type BootstrapCheck = {
|
|
16
17
|
key: "auth" | "update" | "framework" | "model_quality" | "resume_context" | "subskill_catalog" | "create_campaign_subskill";
|
|
@@ -87,6 +88,10 @@ export declare const bootstrapToolDefinitions: {
|
|
|
87
88
|
type: string;
|
|
88
89
|
description: string;
|
|
89
90
|
};
|
|
91
|
+
modelMetadataSource: {
|
|
92
|
+
type: string;
|
|
93
|
+
description: string;
|
|
94
|
+
};
|
|
90
95
|
};
|
|
91
96
|
additionalProperties: boolean;
|
|
92
97
|
};
|
package/dist/tools/bootstrap.js
CHANGED
|
@@ -18,7 +18,7 @@ function toGuidance(check, message) {
|
|
|
18
18
|
return "Fix framework files and rerun bootstrap_create_campaign.";
|
|
19
19
|
}
|
|
20
20
|
if (check === "model_quality") {
|
|
21
|
-
return `Use
|
|
21
|
+
return `Use trusted active-turn metadata before enforcing the campaign model floor: ${getCampaignModelMinimumSummary()}.`;
|
|
22
22
|
}
|
|
23
23
|
if (check === "resume_context") {
|
|
24
24
|
return "Confirm the campaignId exists and is accessible, then retry bootstrap_create_campaign.";
|
|
@@ -98,15 +98,19 @@ export const bootstrapToolDefinitions = [
|
|
|
98
98
|
},
|
|
99
99
|
host: {
|
|
100
100
|
type: "string",
|
|
101
|
-
description: "Optional host label for model-quality preflight, for example Claude Code or Codex.",
|
|
101
|
+
description: "Optional host label for active model-quality preflight, for example Claude Code or Codex.",
|
|
102
102
|
},
|
|
103
103
|
model: {
|
|
104
104
|
type: "string",
|
|
105
|
-
description:
|
|
105
|
+
description: "Optional active host model name from runtime metadata. Do not pass config defaults.",
|
|
106
106
|
},
|
|
107
107
|
reasoningEffort: {
|
|
108
108
|
type: "string",
|
|
109
|
-
description:
|
|
109
|
+
description: "Optional active reasoning setting from runtime metadata. Do not pass config defaults.",
|
|
110
|
+
},
|
|
111
|
+
modelMetadataSource: {
|
|
112
|
+
type: "string",
|
|
113
|
+
description: "Where active model metadata came from, for example codex_turn_metadata, claude_runtime_metadata, claude_session_context, active_turn_metadata, or user_confirmed.",
|
|
110
114
|
},
|
|
111
115
|
},
|
|
112
116
|
additionalProperties: false,
|
|
@@ -129,6 +133,7 @@ export async function bootstrapCreateCampaign(input = {}) {
|
|
|
129
133
|
host: input.host,
|
|
130
134
|
model: input.model,
|
|
131
135
|
reasoningEffort: input.reasoningEffort,
|
|
136
|
+
metadataSource: input.modelMetadataSource,
|
|
132
137
|
});
|
|
133
138
|
const runAuthCheck = async () => {
|
|
134
139
|
let status = await getAuthStatus();
|
|
@@ -188,7 +193,7 @@ export async function bootstrapCreateCampaign(input = {}) {
|
|
|
188
193
|
}
|
|
189
194
|
requiredChecks.push({
|
|
190
195
|
key: "model_quality",
|
|
191
|
-
ok: modelQuality.status
|
|
196
|
+
ok: modelQuality.status !== "warn",
|
|
192
197
|
blocking: false,
|
|
193
198
|
detail: modelQuality.message,
|
|
194
199
|
});
|
|
@@ -3,6 +3,7 @@ export type CampaignModelQualityInput = {
|
|
|
3
3
|
host?: string | null;
|
|
4
4
|
model?: string | null;
|
|
5
5
|
reasoningEffort?: string | null;
|
|
6
|
+
metadataSource?: string | null;
|
|
6
7
|
};
|
|
7
8
|
export type CampaignModelQualityStatus = "ok" | "warn" | "unknown";
|
|
8
9
|
export type CampaignModelQualityResult = {
|
|
@@ -10,6 +11,7 @@ export type CampaignModelQualityResult = {
|
|
|
10
11
|
host: CampaignModelHost;
|
|
11
12
|
model: string | null;
|
|
12
13
|
reasoningEffort: string | null;
|
|
14
|
+
metadataSource: string | null;
|
|
13
15
|
recommendedModel: string;
|
|
14
16
|
recommendedReasoningEffort: string;
|
|
15
17
|
minimumSummary: string;
|
|
@@ -34,8 +36,7 @@ export type CampaignModelQualityConfig = {
|
|
|
34
36
|
};
|
|
35
37
|
warningCopy: {
|
|
36
38
|
ok: string;
|
|
37
|
-
|
|
38
|
-
unknownSettings: string;
|
|
39
|
+
skipped: string;
|
|
39
40
|
belowMinimum: string;
|
|
40
41
|
};
|
|
41
42
|
};
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from "fs";
|
|
2
|
-
import { join } from "path";
|
|
3
|
-
import { resolveSkillsDir } from "../skills.js";
|
|
4
1
|
const DEFAULT_MODEL_QUALITY_CONFIG = {
|
|
5
|
-
version:
|
|
2
|
+
version: 2,
|
|
6
3
|
hosts: {
|
|
7
4
|
claude: {
|
|
8
5
|
label: "Claude Code",
|
|
@@ -36,20 +33,24 @@ const DEFAULT_MODEL_QUALITY_CONFIG = {
|
|
|
36
33
|
},
|
|
37
34
|
},
|
|
38
35
|
warningCopy: {
|
|
39
|
-
ok: "
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
belowMinimum: "Best campaigns need at least {minimumSummary}. Current settings look below that: {currentSettings}. Please switch before continuing, or explicitly say to continue anyway.",
|
|
36
|
+
ok: "Active host model metadata meets the configured campaign floor: {currentSettings}.",
|
|
37
|
+
skipped: "Active host model metadata was not available from a trusted runtime source. Continue without asking the user to switch models.",
|
|
38
|
+
belowMinimum: "Active host metadata reports {currentSettings}, which is below the configured campaign floor: {minimumSummary}. Ask the user to switch before continuing, or explicitly say to continue anyway.",
|
|
43
39
|
},
|
|
44
40
|
};
|
|
45
|
-
|
|
41
|
+
const TRUSTED_METADATA_SOURCE_KEYWORDS = [
|
|
42
|
+
"codex_turn_metadata",
|
|
43
|
+
"claude_runtime_metadata",
|
|
44
|
+
"claude_session_context",
|
|
45
|
+
"active_turn_metadata",
|
|
46
|
+
"user_confirmed",
|
|
47
|
+
];
|
|
46
48
|
const normalize = (value) => String(value ?? "")
|
|
47
49
|
.trim()
|
|
48
50
|
.toLowerCase();
|
|
49
51
|
const normalizeHost = (host) => {
|
|
50
52
|
const normalized = normalize(host);
|
|
51
53
|
if (normalized.includes("claude") ||
|
|
52
|
-
normalized.includes("clod") ||
|
|
53
54
|
normalized.includes("opus") ||
|
|
54
55
|
normalized.includes("sonnet") ||
|
|
55
56
|
normalized.includes("haiku")) {
|
|
@@ -77,42 +78,12 @@ const compareVersion = (candidate, minimum) => {
|
|
|
77
78
|
}
|
|
78
79
|
return 0;
|
|
79
80
|
};
|
|
80
|
-
const extractModelVersions = (model) =>
|
|
81
|
-
|
|
82
|
-
return {
|
|
83
|
-
|
|
84
|
-
...rawConfig,
|
|
85
|
-
hosts: {
|
|
86
|
-
claude: {
|
|
87
|
-
...DEFAULT_MODEL_QUALITY_CONFIG.hosts.claude,
|
|
88
|
-
...(rawConfig.hosts?.claude || {}),
|
|
89
|
-
},
|
|
90
|
-
codex: {
|
|
91
|
-
...DEFAULT_MODEL_QUALITY_CONFIG.hosts.codex,
|
|
92
|
-
...(rawConfig.hosts?.codex || {}),
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
warningCopy: {
|
|
96
|
-
...DEFAULT_MODEL_QUALITY_CONFIG.warningCopy,
|
|
97
|
-
...(rawConfig.warningCopy || {}),
|
|
98
|
-
},
|
|
99
|
-
};
|
|
100
|
-
}
|
|
81
|
+
const extractModelVersions = (model) => {
|
|
82
|
+
const normalized = normalize(model).replace(/(?<=\d)[_-](?=\d)/g, ".");
|
|
83
|
+
return Array.from(normalized.matchAll(/\b(\d+(?:\.\d+){0,2})\b/g)).map((match) => match[1]);
|
|
84
|
+
};
|
|
101
85
|
export function getCampaignModelQualityConfig() {
|
|
102
|
-
|
|
103
|
-
return cachedConfig;
|
|
104
|
-
const configPath = join(resolveSkillsDir(), "create-campaign", "core", "model-quality.json");
|
|
105
|
-
if (!existsSync(configPath)) {
|
|
106
|
-
cachedConfig = DEFAULT_MODEL_QUALITY_CONFIG;
|
|
107
|
-
return cachedConfig;
|
|
108
|
-
}
|
|
109
|
-
try {
|
|
110
|
-
cachedConfig = mergeConfig(JSON.parse(readFileSync(configPath, "utf-8")));
|
|
111
|
-
}
|
|
112
|
-
catch {
|
|
113
|
-
cachedConfig = DEFAULT_MODEL_QUALITY_CONFIG;
|
|
114
|
-
}
|
|
115
|
-
return cachedConfig;
|
|
86
|
+
return DEFAULT_MODEL_QUALITY_CONFIG;
|
|
116
87
|
}
|
|
117
88
|
export function getCampaignModelMinimumSummary(config = getCampaignModelQualityConfig()) {
|
|
118
89
|
return `${config.hosts.claude.minimumModel} with ${config.hosts.claude.minimumReasoningEffort} reasoning or ${config.hosts.codex.minimumModel} with ${config.hosts.codex.minimumReasoningEffort} reasoning`;
|
|
@@ -134,12 +105,12 @@ function modelMeetsMinimum(model, hostConfig, options = {}) {
|
|
|
134
105
|
hostConfig.familyKeywords.every((keyword) => normalizedModel.includes(normalize(keyword)));
|
|
135
106
|
if (!familyMatches)
|
|
136
107
|
return false;
|
|
137
|
-
const versions = extractModelVersions(
|
|
108
|
+
const versions = extractModelVersions(model);
|
|
138
109
|
if (!hostConfig.minimumVersion)
|
|
139
110
|
return true;
|
|
140
111
|
return versions.some((version) => compareVersion(version, hostConfig.minimumVersion) >= 0);
|
|
141
112
|
}
|
|
142
|
-
function
|
|
113
|
+
function findHostConfig(host, model, config) {
|
|
143
114
|
const candidates = host === "unknown"
|
|
144
115
|
? [
|
|
145
116
|
["claude", config.hosts.claude],
|
|
@@ -150,100 +121,63 @@ function findAcceptedHostConfig(host, model, config) {
|
|
|
150
121
|
familyKnownFromHost: host !== "unknown",
|
|
151
122
|
}));
|
|
152
123
|
}
|
|
153
|
-
function
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
if (!model || !reasoningEffort)
|
|
157
|
-
return false;
|
|
158
|
-
const normalizedModel = normalize(model).replace(/[_-]+/g, " ");
|
|
159
|
-
const normalizedReasoning = normalizeReasoning(reasoningEffort);
|
|
160
|
-
if (!normalizedModel.includes("gpt"))
|
|
161
|
-
return false;
|
|
162
|
-
const versions = extractModelVersions(normalizedModel);
|
|
163
|
-
const looksLikeBaseGpt5 = versions.some((version) => version === "5" || version === "5.0");
|
|
164
|
-
if (!looksLikeBaseGpt5)
|
|
165
|
-
return false;
|
|
166
|
-
return (["default", "auto", "standard"].includes(normalizedReasoning) ||
|
|
167
|
-
acceptsReasoning(reasoningEffort, config.hosts.codex));
|
|
124
|
+
function isTrustedMetadataSource(source) {
|
|
125
|
+
const normalized = normalize(source).replace(/[\s-]+/g, "_");
|
|
126
|
+
return TRUSTED_METADATA_SOURCE_KEYWORDS.some((keyword) => normalized.includes(keyword));
|
|
168
127
|
}
|
|
169
128
|
export function evaluateCampaignModelQuality(input = {}) {
|
|
170
129
|
const config = getCampaignModelQualityConfig();
|
|
171
130
|
const host = normalizeHost([input.host, input.model].filter(Boolean).join(" "));
|
|
172
131
|
const model = input.model?.trim() || null;
|
|
173
132
|
const reasoningEffort = input.reasoningEffort?.trim() || null;
|
|
133
|
+
const metadataSource = input.metadataSource?.trim() || null;
|
|
174
134
|
const recommendationHost = host === "claude" ? "claude" : "codex";
|
|
175
135
|
const recommendedHostConfig = config.hosts[recommendationHost];
|
|
176
136
|
const minimumSummary = getCampaignModelMinimumSummary(config);
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
137
|
+
const currentSettings = [
|
|
138
|
+
model ? `model "${model}"` : "unknown model",
|
|
139
|
+
reasoningEffort ? `reasoning "${reasoningEffort}"` : "unknown reasoning",
|
|
140
|
+
metadataSource ? `source "${metadataSource}"` : "unknown source",
|
|
141
|
+
].join(", ");
|
|
142
|
+
const base = {
|
|
143
|
+
host,
|
|
144
|
+
model,
|
|
145
|
+
reasoningEffort,
|
|
146
|
+
metadataSource,
|
|
147
|
+
recommendedModel: recommendedHostConfig.minimumModel,
|
|
148
|
+
recommendedReasoningEffort: recommendedHostConfig.recommendedReasoningEffort,
|
|
149
|
+
minimumSummary,
|
|
150
|
+
metadataStale: false,
|
|
151
|
+
};
|
|
152
|
+
if (!isTrustedMetadataSource(metadataSource) || !model || !reasoningEffort) {
|
|
180
153
|
return {
|
|
154
|
+
...base,
|
|
181
155
|
status: "unknown",
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
reasoningEffort,
|
|
185
|
-
recommendedModel,
|
|
186
|
-
recommendedReasoningEffort,
|
|
187
|
-
minimumSummary,
|
|
188
|
-
confirmationRequired: true,
|
|
189
|
-
metadataStale: false,
|
|
190
|
-
message: formatCopy(config.warningCopy.unknownSettings, {
|
|
191
|
-
minimumSummary,
|
|
192
|
-
currentSettings: "unknown",
|
|
193
|
-
}),
|
|
156
|
+
confirmationRequired: false,
|
|
157
|
+
message: config.warningCopy.skipped,
|
|
194
158
|
};
|
|
195
159
|
}
|
|
196
|
-
const acceptedHostConfig =
|
|
160
|
+
const acceptedHostConfig = findHostConfig(host, model, config);
|
|
197
161
|
const ok = Boolean(acceptedHostConfig && acceptsReasoning(reasoningEffort, acceptedHostConfig[1]));
|
|
198
162
|
if (ok) {
|
|
199
163
|
return {
|
|
164
|
+
...base,
|
|
200
165
|
status: "ok",
|
|
201
166
|
host: acceptedHostConfig?.[0] ?? host,
|
|
202
|
-
|
|
203
|
-
reasoningEffort,
|
|
204
|
-
recommendedModel: acceptedHostConfig?.[1].minimumModel ?? recommendedModel,
|
|
167
|
+
recommendedModel: acceptedHostConfig?.[1].minimumModel ?? base.recommendedModel,
|
|
205
168
|
recommendedReasoningEffort: acceptedHostConfig?.[1].recommendedReasoningEffort ??
|
|
206
|
-
recommendedReasoningEffort,
|
|
207
|
-
minimumSummary,
|
|
169
|
+
base.recommendedReasoningEffort,
|
|
208
170
|
confirmationRequired: false,
|
|
209
|
-
metadataStale: false,
|
|
210
171
|
message: formatCopy(config.warningCopy.ok, {
|
|
211
172
|
minimumSummary,
|
|
212
|
-
currentSettings
|
|
173
|
+
currentSettings,
|
|
213
174
|
}),
|
|
214
175
|
};
|
|
215
176
|
}
|
|
216
|
-
if (looksLikeCodexStaleMetadata(host, model, reasoningEffort, config)) {
|
|
217
|
-
return {
|
|
218
|
-
status: "ok",
|
|
219
|
-
host,
|
|
220
|
-
model,
|
|
221
|
-
reasoningEffort,
|
|
222
|
-
recommendedModel,
|
|
223
|
-
recommendedReasoningEffort,
|
|
224
|
-
minimumSummary,
|
|
225
|
-
confirmationRequired: false,
|
|
226
|
-
metadataStale: true,
|
|
227
|
-
message: formatCopy(config.warningCopy.staleCodexMetadata, {
|
|
228
|
-
minimumSummary,
|
|
229
|
-
currentSettings: "stale Codex host metadata",
|
|
230
|
-
}),
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
const currentSettings = [
|
|
234
|
-
model ? `model "${model}"` : "unknown model",
|
|
235
|
-
reasoningEffort ? `reasoning "${reasoningEffort}"` : "unknown reasoning",
|
|
236
|
-
].join(", ");
|
|
237
177
|
return {
|
|
178
|
+
...base,
|
|
238
179
|
status: "warn",
|
|
239
|
-
host,
|
|
240
|
-
model,
|
|
241
|
-
reasoningEffort,
|
|
242
|
-
recommendedModel,
|
|
243
|
-
recommendedReasoningEffort,
|
|
244
|
-
minimumSummary,
|
|
245
180
|
confirmationRequired: true,
|
|
246
|
-
metadataStale: false,
|
|
247
181
|
message: formatCopy(config.warningCopy.belowMinimum, {
|
|
248
182
|
minimumSummary,
|
|
249
183
|
currentSettings,
|
package/dist/tools/registry.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -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"
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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
|
|
@@ -938,13 +981,19 @@ updates.
|
|
|
938
981
|
- Do not call `mcp__sellable__get_campaigns`.
|
|
939
982
|
- Do not call `mcp__sellable__get_campaign` to hunt for IDs.
|
|
940
983
|
- Do not call `mcp__sellable__create_campaign({ campaignId: ... })` unless the user supplied that id.
|
|
941
|
-
6. Call `mcp__sellable__bootstrap_create_campaign({ flowVersion: "v2", campaignId?, host?, model?, reasoningEffort? })`.
|
|
942
|
-
Pass
|
|
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.
|
|
943
992
|
7. If `safeToProceed !== true`, stop and show `blockingErrors` + `nextStep`.
|
|
944
|
-
8. If `modelQuality.status === "warn"
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
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.
|
|
948
997
|
|
|
949
998
|
## Execute Workflow
|
|
950
999
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version":
|
|
2
|
+
"version": 2,
|
|
3
3
|
"hosts": {
|
|
4
4
|
"claude": {
|
|
5
5
|
"label": "Claude Code",
|
|
@@ -21,9 +21,8 @@
|
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"warningCopy": {
|
|
24
|
-
"ok": "
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"belowMinimum": "Best campaigns need at least {minimumSummary}. Current settings look below that: {currentSettings}. Please switch before continuing, or explicitly say to continue anyway."
|
|
24
|
+
"ok": "Active host model metadata meets the configured campaign floor: {currentSettings}.",
|
|
25
|
+
"skipped": "Active host model metadata was not available from a trusted runtime source. Continue without asking the user to switch models.",
|
|
26
|
+
"belowMinimum": "Active host metadata reports {currentSettings}, which is below the configured campaign floor: {minimumSummary}. Ask the user to switch before continuing, or explicitly say to continue anyway."
|
|
28
27
|
}
|
|
29
28
|
}
|
|
@@ -296,7 +296,12 @@ atomic-mint step:
|
|
|
296
296
|
|
|
297
297
|
0. **verify workspace/sender invariant** (see §Preconditions) — if the
|
|
298
298
|
invariant fails, abort BEFORE `bootstrap_create_campaign`
|
|
299
|
-
1. `bootstrap_create_campaign({ flowVersion: "v2", host?, model?, reasoningEffort? })`
|
|
299
|
+
1. `bootstrap_create_campaign({ flowVersion: "v2", host?, model?, reasoningEffort?, modelMetadataSource? })`
|
|
300
|
+
Pass model metadata only when it comes from active turn/runtime metadata or
|
|
301
|
+
explicit user confirmation that includes both model and effort. Use
|
|
302
|
+
`modelMetadataSource: "claude_session_context"` only when the current Claude
|
|
303
|
+
session context explicitly states both values. Never use inferred config
|
|
304
|
+
defaults, nested Claude sessions, or saved settings files.
|
|
300
305
|
2. If `campaign-shell.json` exists, call `create_campaign({ campaignId })` to
|
|
301
306
|
resume/recover `{ campaignId, watchUrl }`, then
|
|
302
307
|
`update_campaign({ campaignId, campaignBrief, leadSourceType,
|