@sellable/mcp 0.1.556 → 0.1.557
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 +13 -2
- package/agents/registry.json +2 -2
- package/dist/api.js +3 -6
- package/dist/auth.d.ts +0 -6
- package/dist/auth.js +2 -44
- package/dist/refill-run-client.d.ts +0 -5
- package/dist/refill-run-client.js +0 -15
- package/dist/refill-run-loop.d.ts +1 -12
- package/dist/refill-run-loop.js +13 -158
- package/dist/server.js +23 -0
- package/dist/tools/auth.d.ts +0 -5
- package/dist/tools/auth.js +12 -49
- package/dist/tools/campaign-message-preparation.d.ts +0 -62
- package/dist/tools/campaign-message-preparation.js +0 -41
- package/dist/tools/campaigns.js +2 -2
- package/dist/tools/csv-dnc.js +2 -2
- package/dist/tools/evergreen-refill-plan.d.ts +0 -3
- package/dist/tools/evergreen-refill-plan.js +7 -29
- package/dist/tools/find-leads-runs.d.ts +151 -0
- package/dist/tools/find-leads-runs.js +98 -0
- package/dist/tools/leads.d.ts +317 -32
- package/dist/tools/leads.js +171 -10
- package/dist/tools/model-quality.js +4 -6
- package/dist/tools/prompts.d.ts +3 -3
- package/dist/tools/prompts.js +7 -15
- package/dist/tools/provider-preflight.d.ts +65 -2
- package/dist/tools/provider-preflight.js +97 -10
- package/dist/tools/readiness.d.ts +89 -5
- package/dist/tools/readiness.js +66 -0
- package/dist/tools/refill-executors.d.ts +0 -38
- package/dist/tools/refill-executors.js +3 -222
- package/dist/tools/refill-sends-v2.d.ts +1 -118
- package/dist/tools/refill-sends-v2.js +2 -310
- package/dist/tools/refill-sends.d.ts +32 -678
- package/dist/tools/refill-sends.js +13 -274
- package/dist/tools/refill-target-plan.js +14 -486
- package/dist/tools/registry.d.ts +330 -115
- package/dist/tools/registry.js +7 -1
- package/dist/tools/scheduler-fill-capacity.js +1 -1
- package/dist/tools/scheduler-run.d.ts +0 -71
- package/dist/tools/scheduler-run.js +1 -203
- package/dist/tools/setup-evergreen-campaigns.js +1 -1
- package/dist/tools/workspace-context.d.ts +1 -1
- package/dist/tools/workspace-context.js +3 -8
- package/dist/tools/workspace-export.js +2 -2
- package/dist/tools/workspaces.d.ts +2 -48
- package/dist/tools/workspaces.js +5 -48
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +3 -3
- package/skills/create-campaign-v2/SKILL.md +1 -1
- package/skills/create-evergreen-campaigns/SKILL.md +16 -16
- package/skills/find-leads/SKILL.md +48 -630
- package/skills/find-leads-v2/SKILL.md +70 -0
- package/skills/find-leads-v2/core/flow.v1.json +31 -0
- package/skills/refill-sends/SKILL.md +353 -91
- package/skills/refill-sends-v2/SKILL.md +6 -6
- package/skills/refill-sends-v2-workflow/SKILL.md +5 -5
- package/skills/refill-sends-v2-workflow/core/flow.v1.json +8 -8
- package/skills/refill-sends-workflow/SKILL.md +743 -100
- package/skills/refill-sends-workflow/core/flow.v1.json +1 -185
- package/dist/refill-contract.d.ts +0 -157
- package/dist/refill-contract.js +0 -487
- package/skills/refill-sends-workflow/core/contract.v2.json +0 -543
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: find-leads-v2
|
|
3
|
+
description: Canonical approval-gated campaignless lead sourcing state machine.
|
|
4
|
+
visibility: internal
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Find Leads V2
|
|
8
|
+
|
|
9
|
+
This is the canonical campaignless workflow. The durable identity invariant is
|
|
10
|
+
`runId = leadListId`. Resume from product state with `get_find_leads_run`; never
|
|
11
|
+
reconstruct progress from chat memory.
|
|
12
|
+
|
|
13
|
+
## Prerequisites and recovery
|
|
14
|
+
|
|
15
|
+
- Call `get_auth_status`. If login is required, use `start_cli_login` and
|
|
16
|
+
`wait_for_cli_login` before retrying.
|
|
17
|
+
- Require an active workspace. If none is active, use `list_workspaces` and
|
|
18
|
+
`set_active_workspace`.
|
|
19
|
+
- If lifecycle tools, this prompt, or its flow asset are missing/outdated,
|
|
20
|
+
update the Sellable MCP/plugin, restart or reload the host, and retry.
|
|
21
|
+
- Sales Nav requires a connected LinkedIn account with an active Sales Navigator search session.
|
|
22
|
+
- Prospeo requires configured access and enough Prospeo credits for the bounded
|
|
23
|
+
plan.
|
|
24
|
+
- Signal Discovery capacity must be available; otherwise wait or choose one of
|
|
25
|
+
the other providers.
|
|
26
|
+
- For hiring-led targeting, start with `Prospeo` because its job-posting filters
|
|
27
|
+
are native. Run source work in the parent thread; do not dispatch custom source-scout subagents.
|
|
28
|
+
|
|
29
|
+
## Durable flow
|
|
30
|
+
|
|
31
|
+
1. `bootstrap_find_leads({ bootstrapKey, name })`, then show the returned watch
|
|
32
|
+
URL. On restart call `get_find_leads_run({ runId })`; if the link expired use
|
|
33
|
+
`reissue_find_leads_watch_link`. A deleted run/list is terminal: start a new
|
|
34
|
+
run only after explaining that recovery.
|
|
35
|
+
2. Draft a compact source plan: target, provider, filters/signals, sample size,
|
|
36
|
+
import cap, fallback, and expected provider cost/capacity. Ask for explicit
|
|
37
|
+
source-plan approval. Persist it with `update_find_leads_run` action
|
|
38
|
+
`approve_source_plan`. This source-plan approval permits search only.
|
|
39
|
+
3. Choose exactly one provider. Load `get_provider_prompt` for the selected provider only,
|
|
40
|
+
then call `preflight_find_leads_provider` with the current
|
|
41
|
+
run version and prompt/workflow hash. A prompt loaded for another run,
|
|
42
|
+
provider, or memory wildcard is invalid.
|
|
43
|
+
4. Search/sample through `search_sales_nav`, `search_prospeo`, or
|
|
44
|
+
`search_signals`, always passing `findLeadsRunId` and current `runVersion`.
|
|
45
|
+
For Signal, persist the approved post selection with
|
|
46
|
+
`select_promising_posts` using the same run and tab.
|
|
47
|
+
5. Present the bounded import plan and ask for a distinct import approval.
|
|
48
|
+
Persist `approve_import`; never treat source-plan approval as import approval.
|
|
49
|
+
6. Call `import_leads` with exactly one target: `findLeadsRunId`. Pass the
|
|
50
|
+
current run version and provider search/tab receipt. Never pass a campaign
|
|
51
|
+
target on this path.
|
|
52
|
+
7. Call `wait_for_lead_list_ready({ findLeadsRunId })` until ready, empty,
|
|
53
|
+
failed, or cancelled. Re-read the snapshot after timeout/retry.
|
|
54
|
+
8. Review rows with `get_rows_minimal({ tableId: runId })`. For terminal empty
|
|
55
|
+
runs, export remains valid and returns a header-only CSV.
|
|
56
|
+
9. Export with `export_table_csv({ tableId: runId })`. Do not create a second
|
|
57
|
+
export tool. Export failure must not mutate the run.
|
|
58
|
+
|
|
59
|
+
An optional Add to Campaign action is only a suggestion after review when the
|
|
60
|
+
user explicitly asks. It is never an automatic MCP step.
|
|
61
|
+
|
|
62
|
+
## Terminal states
|
|
63
|
+
|
|
64
|
+
- `failed`: show stable code, retryability, and exact next action. Resume the
|
|
65
|
+
same run when retryable.
|
|
66
|
+
- `cancelled`: do not search or import again; review/export existing rows.
|
|
67
|
+
- `ready` or `empty`: review and export.
|
|
68
|
+
|
|
69
|
+
Progress extensions and background task protocols are optional host hints, not
|
|
70
|
+
dependencies. Ordinary registered tools and the durable snapshot are enough.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"workflow": "find-leads-v2",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"identity": "runId = leadListId",
|
|
5
|
+
"providers": {
|
|
6
|
+
"sales-nav": { "prompt": "sales-nav", "searchTool": "search_sales_nav" },
|
|
7
|
+
"prospeo": { "prompt": "prospeo", "searchTool": "search_prospeo" },
|
|
8
|
+
"signal-discovery": { "prompt": "signal-discovery", "searchTool": "search_signals" }
|
|
9
|
+
},
|
|
10
|
+
"invariants": [
|
|
11
|
+
"Resume every existing run with get_find_leads_run.",
|
|
12
|
+
"A current source-plan approval permits search only.",
|
|
13
|
+
"A distinct current import approval is required before materialization.",
|
|
14
|
+
"Load and preflight the selected provider only.",
|
|
15
|
+
"Export the source table with export_table_csv using tableId equal to runId."
|
|
16
|
+
],
|
|
17
|
+
"states": [
|
|
18
|
+
{ "id": "prerequisites", "tools": ["get_auth_status", "get_active_workspace"], "transitions": { "ready": "run_watch" } },
|
|
19
|
+
{ "id": "run_watch", "tools": ["bootstrap_find_leads", "get_find_leads_run", "reissue_find_leads_watch_link"], "transitions": { "new": "source_plan", "resume_search": "search_sample", "resume_import": "materializing", "terminal": "review" } },
|
|
20
|
+
{ "id": "source_plan", "transitions": { "drafted": "source_plan_approval" } },
|
|
21
|
+
{ "id": "source_plan_approval", "tools": ["update_find_leads_run"], "transitions": { "approved": "provider_preflight", "cancel": "cancelled" } },
|
|
22
|
+
{ "id": "provider_preflight", "tools": ["get_provider_prompt", "preflight_find_leads_provider"], "transitions": { "ready": "search_sample", "blocked": "failed" } },
|
|
23
|
+
{ "id": "search_sample", "tools": ["search_sales_nav", "search_prospeo", "search_signals", "select_promising_posts"], "transitions": { "sampled": "import_plan_approval", "retryable_error": "provider_preflight", "cancel": "cancelled" } },
|
|
24
|
+
{ "id": "import_plan_approval", "tools": ["update_find_leads_run"], "transitions": { "approved": "materializing", "revise": "source_plan", "cancel": "cancelled" } },
|
|
25
|
+
{ "id": "materializing", "tools": ["import_leads", "wait_for_lead_list_ready", "get_find_leads_run"], "transitions": { "ready": "review", "empty": "review", "failed": "failed", "cancelled": "cancelled" } },
|
|
26
|
+
{ "id": "review", "tools": ["get_rows_minimal"], "transitions": { "export": "export" } },
|
|
27
|
+
{ "id": "export", "tools": ["export_table_csv"], "transitions": { "done": "review" } },
|
|
28
|
+
{ "id": "failed", "tools": ["get_find_leads_run"], "transitions": { "retry": "provider_preflight", "export_existing": "export" } },
|
|
29
|
+
{ "id": "cancelled", "tools": ["get_find_leads_run"], "transitions": { "review_existing": "review", "export_existing": "export" } }
|
|
30
|
+
]
|
|
31
|
+
}
|
|
@@ -58,97 +58,359 @@ allowed-tools:
|
|
|
58
58
|
|
|
59
59
|
# Refill Sends
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
`ready_buffer_exists_is_not_complete`, never completion.
|
|
138
|
-
|
|
139
|
-
<!-- REFILL_CONTRACT_GENERATED:START -->
|
|
140
|
-
## Generated refill contract metadata
|
|
141
|
-
|
|
142
|
-
contractVersion: 2.0.0
|
|
143
|
-
cacheVersion: refill-contract-v1
|
|
144
|
-
contractHash: e54ba0f80bc534fd70fd8c10c1caab109fe9a91c205cfc423f5f6735cd53fdc1
|
|
61
|
+
Use this public command wrapper for plain operator requests such as "fill",
|
|
62
|
+
"refill sends", "max out sends", "load everyone up", or "fill horizon sends".
|
|
63
|
+
|
|
64
|
+
Host command names:
|
|
65
|
+
|
|
66
|
+
- Claude Code: `/sellable:refill-sends`
|
|
67
|
+
- Codex: `$sellable:refill-sends`
|
|
68
|
+
|
|
69
|
+
Accepted invocation flags in the same user request:
|
|
70
|
+
|
|
71
|
+
- `--yolo`: auto-accept the rendered bounded refill packet after the required
|
|
72
|
+
fresh state reread.
|
|
73
|
+
- `workspaceId: <id>`: required for scheduled automation and `--yolo`; pass it
|
|
74
|
+
through on every refill MCP tool call instead of relying on shared config
|
|
75
|
+
state.
|
|
76
|
+
- `--sender <name-or-id>`: scope to a specific sender; repeat for multiple
|
|
77
|
+
senders.
|
|
78
|
+
- `--until <YYYY-MM-DD>`: fill through that sender-local date, inclusive,
|
|
79
|
+
instead of the default scheduler-forward 48-hour target window.
|
|
80
|
+
- `--target-date <YYYY-MM-DD>`: fill only that sender-local date. This means
|
|
81
|
+
prepare rows for scheduler-fillable slots on that date, not every remaining
|
|
82
|
+
daily-limit slot and not an inclusive through-date.
|
|
83
|
+
- `senderIds: <id>, <id>` or `senderNames: <name>, <name>`: explicit selector
|
|
84
|
+
alternatives when the host preserves natural-language arguments better than
|
|
85
|
+
shell-style flags.
|
|
86
|
+
- `untilDate: YYYY-MM-DD`: explicit date selector alternative when the host
|
|
87
|
+
preserves natural-language arguments better than shell-style flags.
|
|
88
|
+
- `targetDate: YYYY-MM-DD`: exact-date selector alternative when the host
|
|
89
|
+
preserves natural-language arguments better than shell-style flags.
|
|
90
|
+
|
|
91
|
+
When the host can call typed MCP tools, start with:
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
refill_sends({ yolo?: boolean, executionMode?: "manual" | "scheduled" | "yolo", requireWorkspace?: boolean, workspaceId?: string, senders?: string[], senderIds?: string[], senderNames?: string[], horizonSendDays?: number, untilDate?: "YYYY-MM-DD", targetDate?: "YYYY-MM-DD" })
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
That command helper normalizes arguments and returns the execution contract. In
|
|
98
|
+
non-yolo mode it does not mutate. In `--yolo`, it may execute exactly one safe
|
|
99
|
+
bounded primitive from the fresh `target.globalActionQueue[0]`, then reread and
|
|
100
|
+
return the new target plan; currently safe primitives are paid-credit refresh,
|
|
101
|
+
existing-row message preparation, generated-message approval, receipt-proven
|
|
102
|
+
same-source row copy, and read-only wait rereads. Same-source copy/source
|
|
103
|
+
fallback is safe only after receipt-proven exhaustion:
|
|
104
|
+
`hasMoreFrontierRows:false`, zero `approvalCandidates`, no `stuckActiveCells`,
|
|
105
|
+
and no non-terminal `approvedNotDispatched` work. It does not run unbounded approval, lower
|
|
106
|
+
paid-InMail thresholds, switch source families, create campaigns, launch, send,
|
|
107
|
+
or write scheduler rows. Continue with the workflow below for route selection,
|
|
108
|
+
state rereads, approval gating, source import, preparation, and bounded
|
|
109
|
+
approval.
|
|
110
|
+
|
|
111
|
+
## Workspace Contract
|
|
112
|
+
|
|
113
|
+
First resolve the target workspace id from the user's request, automation config,
|
|
114
|
+
or install-time workspace mapping. Pass `workspaceId` on every scheduled or
|
|
115
|
+
`--yolo` refill tool call, including setup/read calls such as
|
|
116
|
+
`refill_sends`, `get_refill_target_plan`, `list_senders`,
|
|
117
|
+
`get_sender_routing`, `resolve_campaign_fill_route`,
|
|
118
|
+
`get_campaign_refill_state`, `get_scheduler_fill_capacity`,
|
|
119
|
+
`run_scheduler_sweep`, and any later refill mutation covered by the packet.
|
|
120
|
+
Missing `workspaceId` in scheduled or `--yolo` mode is a blocker; stop with
|
|
121
|
+
`WORKSPACE_REQUIRED` instead of running against an implicit or guessed
|
|
122
|
+
workspace.
|
|
123
|
+
|
|
124
|
+
Do not solve scheduled or `--yolo` workspace uncertainty by changing the shared
|
|
125
|
+
active workspace. Manual interactive workspace switching remains a separate
|
|
126
|
+
diagnostic/setup flow, outside automation.
|
|
127
|
+
|
|
128
|
+
Examples:
|
|
129
|
+
|
|
130
|
+
```text
|
|
131
|
+
refill_sends({ yolo:true, executionMode:"yolo", requireWorkspace:true, workspaceId:"cmlq1v8ms0000jx04ang4hi7e" })
|
|
132
|
+
get_refill_target_plan({ intent:"plain", approvalMode:"approve", workspaceId:"cmlq1v8ms0000jx04ang4hi7e" })
|
|
133
|
+
list_senders({ workspaceId:"cmlq1v8ms0000jx04ang4hi7e" })
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Clover scheduled automation must name the Clover workspace explicitly:
|
|
145
137
|
|
|
146
138
|
```text
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
release identities (independent of semantic hash): mcpPackageVersion, installPackageVersion, codexPluginVersion
|
|
150
|
-
forbidden: direct_send, raw_scheduler_write, campaign_create, campaign_archive_delete, threshold_lowering, unselected_source_mutation, unapproved_campaign_start, sender_config_write
|
|
151
|
-
terminal: projected_full, concrete_blocker, deadline_reached, iteration_limit, operator_stopped, capped_by_scheduler, loaded_awaiting_scheduler, lanes_exhausted, not_an_evergreen_workspace, no_refillable_campaigns
|
|
152
|
-
ready_buffer_exists_is_not_complete
|
|
139
|
+
refill_sends({ yolo:false, executionMode:"scheduled", requireWorkspace:true, workspaceId:"cmlq1v8ms0000jx04ang4hi7e" })
|
|
140
|
+
get_refill_target_plan({ intent:"plain", approvalMode:"mark_ready", workspaceId:"cmlq1v8ms0000jx04ang4hi7e" })
|
|
153
141
|
```
|
|
154
|
-
|
|
142
|
+
|
|
143
|
+
First call `get_auth_status({})`. If auth is not OK, follow the returned login
|
|
144
|
+
guidance before route resolution. Do not run refill research against an implicit
|
|
145
|
+
or guessed workspace.
|
|
146
|
+
|
|
147
|
+
Treat "refill senders", "fill senders", "load everyone up", and "max out
|
|
148
|
+
senders" as sender-scoped requests. The target set is senders enrolled in active
|
|
149
|
+
campaign-backed sequence campaigns, not the first active campaign returned by a
|
|
150
|
+
resolver.
|
|
151
|
+
|
|
152
|
+
Goal-mode continuation: a skill cannot create or invoke `/goal` by itself. When
|
|
153
|
+
this command is already running inside an active Codex goal, keep that goal open
|
|
154
|
+
until every selected sender lane is filled by projected coverage
|
|
155
|
+
(`sent + scheduled`) for the scheduler-forward target window, Christian
|
|
156
|
+
explicitly stops/statuses the run, or a concrete non-scheduler blocker appears.
|
|
157
|
+
Do not call the goal complete or blocked only because the current state is
|
|
158
|
+
`awaiting_scheduler_after_ready_buffer`; treat it as loaded, awaiting scheduler.
|
|
159
|
+
|
|
160
|
+
Load the internal workflow prompt and deterministic flow asset before taking
|
|
161
|
+
any operational step:
|
|
162
|
+
|
|
163
|
+
```text
|
|
164
|
+
get_subskill_prompt({ subskillName: "refill-sends-workflow" })
|
|
165
|
+
get_subskill_asset({ subskillName: "refill-sends-workflow", assetPath: "core/flow.v1.json" })
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Continue both loads until `hasMore:false`; parse the flow JSON and verify
|
|
169
|
+
`workflow:"refill-sends-workflow"` with a `v1` version. Then follow that
|
|
170
|
+
workflow exactly. The default path is read-only research: compute the refill
|
|
171
|
+
target plan first, resolve the route, identify the sender-relevant campaign
|
|
172
|
+
that most recently had scheduler-owned sends, read refill state for that target,
|
|
173
|
+
report the next safe step using campaign names first, and stop before mutation
|
|
174
|
+
unless the user has explicitly approved the exact workspace,
|
|
175
|
+
campaign/table/source ids, caps/dates, approval mode, expected side effects,
|
|
176
|
+
and stop/rollback condition.
|
|
177
|
+
|
|
178
|
+
Immediately after loading the internal workflow, call
|
|
179
|
+
`get_refill_target_plan`. The target plan is the canonical first fact receipt:
|
|
180
|
+
eligible senders, selected sender-local days, gross target, actual sent
|
|
181
|
+
coverage, scheduler-owned scheduled coverage across active enrolled campaigns,
|
|
182
|
+
projected coverage (`sent + scheduled`), inferred per-sender send lane/action
|
|
183
|
+
selections, ready buffer, remaining projected gap, paid-InMail credit/threshold
|
|
184
|
+
feasibility, `targetShapeRevision`, and `stateRevision`. Refill target lanes are
|
|
185
|
+
connection invites (`send_invite`), standalone paid InMails
|
|
186
|
+
(`send_inmail_closed`), or unified Sales Nav cascades represented publicly as
|
|
187
|
+
`send_inmail_closed` with `campaignClassification:"sales_nav_cascade"`. For a
|
|
188
|
+
Sales Nav cascade, refill the selected campaign first; its sequence can route
|
|
189
|
+
prospects to Open InMail, paid InMail while fresh credits are >= 5, or
|
|
190
|
+
same-campaign connection fallback without asking for separate open/paid/
|
|
191
|
+
connection campaigns. DMs (`send_dm`) are follow-up actions, not refill horizon
|
|
192
|
+
target capacity, and must not be counted as refill sent, scheduled, or ready
|
|
193
|
+
coverage. When `actionTypes` are omitted, trust the target plan's inferred lane
|
|
194
|
+
rather than asking which campaign class to fill. If a stale target plan selects
|
|
195
|
+
`send_dm` or `send_inmail_open` as the lane, stop and re-plan with the current
|
|
196
|
+
planner before mutation.
|
|
197
|
+
Short form: trust the target plan's inferred lane when it is a connection invite,
|
|
198
|
+
paid-InMail refill lane, or unified Sales Nav cascade.
|
|
199
|
+
Connection-only evergreen campaigns with exact `["send_invite"]` sequence proof
|
|
200
|
+
are plain invite capacity: treat them as `selectedLane:"send_invite"` only. Do
|
|
201
|
+
not infer DM, InMail, Sales Nav cascade, paid-credit refresh, message
|
|
202
|
+
generation, follow-up, sequence mutation, launch/start, scheduling override, or
|
|
203
|
+
direct-send work from a connection-only lane.
|
|
204
|
+
|
|
205
|
+
Structured planner packet:
|
|
206
|
+
|
|
207
|
+
- `target.eligibleSenderLedger` is the public sender eligibility ledger.
|
|
208
|
+
- `target.senderRefillPlans[]` is the canonical sender-level packet; read and
|
|
209
|
+
display it before mutation.
|
|
210
|
+
- Each sender packet includes `campaignRanking.options`, `sourcePlan`,
|
|
211
|
+
`refillReceipt`, `nextActions`, and `manualAlternates`.
|
|
212
|
+
- `refillReceipt` is the public ladder receipt. It carries the selected
|
|
213
|
+
campaign/sender/lane summary, skipped rungs, existing-row frontier proof, and
|
|
214
|
+
any absolute `wait.deadlineAt`.
|
|
215
|
+
- Preserve these coverage labels exactly: `Need to prepare`, `Goal`,
|
|
216
|
+
`Already sent`, `Scheduled`, `Ready and waiting to be scheduled`, and
|
|
217
|
+
`Still need`.
|
|
218
|
+
- `target.globalActionQueue` is the only cross-sender yolo execution queue.
|
|
219
|
+
Execute exactly one globally ranked primitive from
|
|
220
|
+
`target.globalActionQueue[0]`, then rerun `get_refill_target_plan` with the
|
|
221
|
+
same `workspaceId` before
|
|
222
|
+
choosing another action.
|
|
223
|
+
- `manualAlternates` are not yolo actions. Threshold lowering and campaign
|
|
224
|
+
creation are manual continuations only.
|
|
225
|
+
|
|
226
|
+
Refill action ladder: approve generated rows only when an explicit bounded
|
|
227
|
+
approval gate exists, process all existing same-campaign unenriched/unprepared
|
|
228
|
+
rows in bounded batches before any source work, then copy bounded net-new rows
|
|
229
|
+
from the selected source (`selectedLeadListId`, provider, and source
|
|
230
|
+
fingerprint preserved), then use provider-aligned source-more. A new source or
|
|
231
|
+
provider switch changes the reply-rate baseline and is a manual alternate, not a
|
|
232
|
+
`--yolo` side effect.
|
|
233
|
+
Source/copy/fallback requires receipt-proven exhaustion of earlier rungs:
|
|
234
|
+
`existingRowFrontier.hasMoreFrontierRows:false`, zero `approvalCandidates`, no
|
|
235
|
+
fresh active prep, no `stuckActiveCells`, and no non-terminal
|
|
236
|
+
`approvedNotDispatched` rows. Treat anomalies, `stuckActiveCells`, and
|
|
237
|
+
non-terminal `approvedNotDispatched` as diagnose-and-report gates, not
|
|
238
|
+
exhaustion. Terminal `approvedNotDispatched` blockers may be reported, then the
|
|
239
|
+
ladder can proceed.
|
|
240
|
+
|
|
241
|
+
Run-local paid-credit guard: in `--yolo`, the `refill_sends` MCP command
|
|
242
|
+
automatically maintains a `refreshedPaidInmailSenderIds` set for the current
|
|
243
|
+
command call. If its first target plan has stale/missing paid-InMail credit
|
|
244
|
+
facts, it refreshes each selected sender at most once, reruns
|
|
245
|
+
`get_refill_target_plan`, and returns the post-refresh `targetPlan` before
|
|
246
|
+
choosing the next prep/source-copy/bounded-approval/read-only wait action. If fresh facts are still below
|
|
247
|
+
threshold, below-threshold paid-InMail facts fall back to an existing connection
|
|
248
|
+
lane, the same Sales Nav cascade campaign's connection branch, or a manual
|
|
249
|
+
continuation.
|
|
250
|
+
|
|
251
|
+
Freshness gate precedes scheduler wait: if any selected
|
|
252
|
+
`target.senderRefillPlans[].paidInmail.status` is `missing_credit_facts` or
|
|
253
|
+
`stale_credit_facts`, or the target plan contains a
|
|
254
|
+
`refresh_paid_inmail_credits` candidate, do not enter `wait_for_scheduler` even
|
|
255
|
+
when `remainingReadyOrProjectedGap:0`. Refresh the exact selected sender credit
|
|
256
|
+
facts once, rerun `get_refill_target_plan`, and only then decide whether
|
|
257
|
+
scheduler wait is the next safe action. If facts remain missing/stale after the
|
|
258
|
+
single refresh attempt, stop with a paid-InMail freshness blocker instead of
|
|
259
|
+
waiting on scheduler pickup.
|
|
260
|
+
The standalone MCP refresh surface is the scoped route
|
|
261
|
+
`/api/v3/mcp/senders/:senderId/refresh-inmail-credits` with explicit
|
|
262
|
+
`workspaceId`; do not use active-workspace mutation as the automation control
|
|
263
|
+
path.
|
|
264
|
+
|
|
265
|
+
Compact refill lessons: sender-level target plan is final truth; trust
|
|
266
|
+
`schedulerGate.sendable` and scheduler gate blockers, not raw
|
|
267
|
+
`unipileAccountStatus` labels alone; use compact prep status checks for
|
|
268
|
+
long-running jobs; reread target plans after prep or cancel; treat ready rows as
|
|
269
|
+
intermediate; avoid huge parallel target-plan reads when output is large. If a
|
|
270
|
+
campaign produces prepared/ready rows but sender-level projected coverage does
|
|
271
|
+
not move after one bounded settle loop, pivot to compact prep status or a
|
|
272
|
+
scheduler-proven lane. Do not keep waiting on campaign-level ready counts.
|
|
273
|
+
|
|
274
|
+
For exact-date requests, pass `targetDate` to `get_refill_target_plan`. If you
|
|
275
|
+
need raw proof, call the read-only `get_scheduler_fill_capacity` query for the
|
|
276
|
+
same sender/action/date; it tells the MCP how many cells the product scheduler
|
|
277
|
+
will try to place and does not import, approve, schedule, refresh credits, or
|
|
278
|
+
mutate.
|
|
279
|
+
When the refill loop has ready rows and needs scheduler pickup now, use
|
|
280
|
+
`run_scheduler_sweep` with the same explicit `workspaceId`; it can place cells
|
|
281
|
+
within existing scheduler gates and returns the receipt, but it never sends or
|
|
282
|
+
bypasses limits.
|
|
283
|
+
Scheduler-run receipt interpretation: `cellsConsidered is allocation-attempt
|
|
284
|
+
count`, not total ready supply, while `readyCellsFound` is ready inventory found
|
|
285
|
+
before prefilters. Inspect `campaignScopeSummary` before assuming the selected
|
|
286
|
+
refill campaign/table was included; if absent, do not infer that target was
|
|
287
|
+
ready-but-blocked. Interpret `prefiltered` as ready cells removed before
|
|
288
|
+
allocation, `skipped` as considered cells blocked by scheduler gates, and
|
|
289
|
+
`deferred` as considered cells waiting on windows/capacity/cooldown. For ready
|
|
290
|
+
closed-InMail cells with stale paid-credit prefilter/defer reasons, refresh
|
|
291
|
+
paid-InMail credits once through existing tools, then rerun `run_scheduler_sweep`
|
|
292
|
+
or read `action:"status"`; `refresh_paid_inmail_credits_then_rerun` is that
|
|
293
|
+
path. `wait_for_capacity_or_window` means report loaded/capped/waiting and do
|
|
294
|
+
not source or prep more rows; `no_ready_cells_continue_refill_prep` means return
|
|
295
|
+
to the refill/prep ladder. Do not treat `cellsScheduled:0` alone as failure.
|
|
296
|
+
If the target plan is complete by projected coverage, report that the selected
|
|
297
|
+
target is already filled and no-op without asking for approval. If the ready
|
|
298
|
+
buffer covers the projected gap, paid InMail credit facts are fresh for every
|
|
299
|
+
selected paid-InMail lane, but scheduled coverage is still short, keep the run
|
|
300
|
+
open in a persistent read-only scheduler wait loop. Poll
|
|
301
|
+
`get_refill_target_plan` every 60-120 seconds, or on the host's next continuation
|
|
302
|
+
interval, until projected coverage fills the target, a concrete non-scheduler
|
|
303
|
+
blocker appears, or Christian explicitly asks to stop or only receive a status
|
|
304
|
+
report. Treat `awaiting_scheduler_after_ready_buffer` as an in-progress wait
|
|
305
|
+
state, not a close-out condition.
|
|
306
|
+
Wait actions are gates, not competing goals. When `wait_for_active_work` or
|
|
307
|
+
`wait_for_scheduler` includes receipt `wait.deadlineAt`, honor that absolute
|
|
308
|
+
deadline; if it is expired on this call, escalate to diagnostics with the
|
|
309
|
+
receipt evidence instead of issuing another blind wait.
|
|
310
|
+
If paid InMail credit facts are stale or missing and the first target plan
|
|
311
|
+
contains `refresh_paid_inmail_credits`, do not present that as the operator's
|
|
312
|
+
next action in `--yolo`. Do not present paid-credit refresh as the next operator
|
|
313
|
+
action after `refill_sends` returns `autoPaidInmailRefresh` and the
|
|
314
|
+
post-refresh `targetPlan`. Trust `refill_sends.autoPaidInmailRefresh`: it should
|
|
315
|
+
show the exact sender ids refreshed once, sender-credit-cache write receipts,
|
|
316
|
+
and a returned post-refresh `targetPlan`. Continue from that post-refresh packet.
|
|
317
|
+
If paid InMail is below threshold after the fresh credit read, report the exact
|
|
318
|
+
campaign/table/column threshold action or same-campaign connection fallback;
|
|
319
|
+
`--yolo` does not lower paid-InMail thresholds or create campaigns.
|
|
320
|
+
|
|
321
|
+
If the plain route's managed waterfall targets are stale, for example skipped
|
|
322
|
+
targets show archived/completed shared slots or the returned targets do not cover
|
|
323
|
+
the named sender, immediately run the active route refetch before declaring a
|
|
324
|
+
sender blocked. Current dashboard-active `PAUSED` campaign-backed sequence
|
|
325
|
+
campaigns are start-eligible refill candidates; read refill state before deciding
|
|
326
|
+
whether to prep, approve, start, or skip. Do not treat them as archived inventory.
|
|
327
|
+
|
|
328
|
+
For interactive Codex or Claude Code sessions, that approval must use the
|
|
329
|
+
host-native structured question gate, not plain chat:
|
|
330
|
+
|
|
331
|
+
- Codex: use `request_user_input`.
|
|
332
|
+
- Claude Code: use `AskUserQuestion`.
|
|
333
|
+
|
|
334
|
+
The approval question must present the final refill step with exactly two
|
|
335
|
+
choices: `Accept` and `Decline`. Render the full operator output packet in
|
|
336
|
+
normal chat immediately before opening the structured approval question so it
|
|
337
|
+
can be displayed as Markdown. The chat packet must include workspace, sender
|
|
338
|
+
scope, a campaign-by-campaign table with campaign name, sender names, action,
|
|
339
|
+
target count/cap, source/list, and blocker/skip reason, then exact ids,
|
|
340
|
+
expected side effects, forbidden actions, and the stop condition. The structured
|
|
341
|
+
question body must be compact and refer back to the posted packet instead of
|
|
342
|
+
duplicating it. Treat `Accept` as permission for only the rendered target, caps,
|
|
343
|
+
mode, and side effects. Treat `Decline` as a hard stop with no mutation.
|
|
344
|
+
|
|
345
|
+
If Christian includes `--yolo` in the same refill request, treat that flag as
|
|
346
|
+
auto-accept for the rendered bounded refill packet after the required fresh state
|
|
347
|
+
reread. For sender-scoped language with no named senders, `--yolo` means all
|
|
348
|
+
eligible healthy senders enrolled in active campaign-backed sequence campaigns in
|
|
349
|
+
the requested `workspaceId`. Without `--yolo`, if Christian did not name senders, ask
|
|
350
|
+
which eligible enrolled senders to refill before choosing campaigns or mutating.
|
|
351
|
+
|
|
352
|
+
`--yolo` only covers the exact sender set, per-sender target campaigns, caps,
|
|
353
|
+
approval mode, and side effects in the packet. It may authorize `start_campaign`
|
|
354
|
+
only for selected `PAUSED`, dashboard-active, campaign-backed sequence refill
|
|
355
|
+
targets when the rendered packet names the exact campaign ids and start side
|
|
356
|
+
effect. Starting a paused campaign can let the product scheduler schedule/send
|
|
357
|
+
approved eligible sequence actions, so include that expected side effect in the
|
|
358
|
+
packet. It does not authorize starting unrelated, archived, completed, draft, or
|
|
359
|
+
direct campaigns, separate launch/send actions, archive or delete cleanup,
|
|
360
|
+
direct scheduler writes, sender reassignment, paid-InMail threshold changes,
|
|
361
|
+
connection campaign creation, paid-InMail credit refreshes outside the exact
|
|
362
|
+
rendered sender packet, or campaigns outside those
|
|
363
|
+
selected for the eligible sender set. Stop and re-plan if the route, sender set,
|
|
364
|
+
ids, caps, blockers, paid-InMail feasibility, action class, or side-effect class
|
|
365
|
+
drift before mutation. Sent/scheduled counts increasing toward the approved
|
|
366
|
+
target are expected progress:
|
|
367
|
+
they change `stateRevision`, not `targetShapeRevision`, and do not require a
|
|
368
|
+
second approval.
|
|
369
|
+
|
|
370
|
+
In `--yolo`, continue as far as the rendered packet safely allows. After each
|
|
371
|
+
apply/prep/source-copy/bounded-approval/read-only wait result, reread state, settle processing when needed, and move to
|
|
372
|
+
the next selected sender or start-eligible same-packet campaign instead of
|
|
373
|
+
stopping after the first partial result. If no in-packet safe action remains,
|
|
374
|
+
return concrete continuation options with campaign names, exact ids, which option
|
|
375
|
+
is still covered by the current packet, and which option needs a new approval
|
|
376
|
+
packet.
|
|
377
|
+
|
|
378
|
+
For `--yolo` fill/schedule requests, completion means projected saturation
|
|
379
|
+
(`sent + scheduled`) for the scheduler-forward target window, not merely
|
|
380
|
+
prepared/approved/ready rows. Maintain a target-window saturation ledger per
|
|
381
|
+
selected sender: selected send days, gross capacity, actual sent cells, future
|
|
382
|
+
scheduler-owned scheduled cells with non-null `scheduledFor`, projected count,
|
|
383
|
+
ready-to-schedule buffer, remaining projected gap, paid-InMail feasibility,
|
|
384
|
+
`targetShapeRevision`, `stateRevision`, and the next MCP primitive that can
|
|
385
|
+
reduce the gap. After every apply/prep/source-copy/bounded-approval/read-only wait result, wait for processing, reread
|
|
386
|
+
the target plan/refill state, recompute the ledger, then keep applying safe
|
|
387
|
+
bounded actions until projected coverage fills the target window or a concrete
|
|
388
|
+
non-scheduler blocker is proven.
|
|
389
|
+
If ready rows cover the projected gap but the scheduler has not picked them up
|
|
390
|
+
yet, report loaded, awaiting scheduler and run the persistent read-only
|
|
391
|
+
scheduler wait loop. Do not finish the refill goal, mark it complete, or mark it
|
|
392
|
+
blocked only because it is still `awaiting_scheduler_after_ready_buffer`; keep
|
|
393
|
+
waiting unless Christian stops the run or the host cannot continue.
|
|
394
|
+
|
|
395
|
+
In `--yolo`, the default fill target is the scheduler-forward 48-hour window
|
|
396
|
+
unless `--target-date`/`targetDate`, `--until`/`untilDate`, or an explicit
|
|
397
|
+
compatibility `horizonSendDays` is provided. If a target date is provided,
|
|
398
|
+
compute bounded gaps for only that sender-local date using scheduler-fillable
|
|
399
|
+
slots. If an until date is provided, compute bounded gaps through that
|
|
400
|
+
sender-local date inclusive, skipping no-send days and never extending beyond
|
|
401
|
+
that date without a new packet. For each target sender, compute the bounded gap
|
|
402
|
+
from that sender's healthy daily capacity, existing future scheduler-owned
|
|
403
|
+
scheduled sends, and rows already ready to schedule across active campaigns
|
|
404
|
+
enrolled with that sender. Then pick the best same-sender campaign to fill the
|
|
405
|
+
gap: prefer recent/future scheduler-owned sends for that sender, then strongest
|
|
406
|
+
recent result evidence, then source health. Do not stop
|
|
407
|
+
after filling only one sender when the request was sender-scoped. If a
|
|
408
|
+
same-source copy hits the campaign-table row cap, split the current source into
|
|
409
|
+
a bounded LinkedIn profile source list, confirm only that smaller list into the
|
|
410
|
+
same campaign, and operate on the copied review batch. Do not fall back to
|
|
411
|
+
on-demand campaigns or unrelated active-campaign fills.
|
|
412
|
+
|
|
413
|
+
Public concepts are regular campaign and evergreen campaign. Internal direct
|
|
414
|
+
campaign types are unsupported refill targets. `fill_campaign_horizon` is only a
|
|
415
|
+
legacy evergreen-only lower-level primitive after route and refill-state
|
|
416
|
+
evidence proves an evergreen target.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: refill-sends-v2
|
|
3
3
|
description: Execute refill sends v2 through the fenced evergreen refill loop, with dry-run and resume support.
|
|
4
|
-
visibility:
|
|
4
|
+
visibility: public
|
|
5
5
|
allowed-tools:
|
|
6
|
-
-
|
|
6
|
+
- mcp__sellable__refill_sends_v2
|
|
7
7
|
- mcp__sellable__get_refill_plan_v2
|
|
8
8
|
- mcp__sellable__get_subskill_prompt
|
|
9
9
|
- mcp__sellable__get_subskill_asset
|
|
@@ -24,7 +24,7 @@ Host command names:
|
|
|
24
24
|
- Claude Code: `/sellable:refill-sends-v2`
|
|
25
25
|
- Codex: `$sellable:refill-sends-v2`
|
|
26
26
|
|
|
27
|
-
`
|
|
27
|
+
`refill_sends_v2` is the execution surface. In real-run mode it starts or
|
|
28
28
|
resumes a fenced refill run, reads a fresh packet, executes only the packet's
|
|
29
29
|
named bounded work, verifies the result, and returns either a terminal report, a
|
|
30
30
|
blocked report, or an in-progress resume handle. In dry-run mode it stays
|
|
@@ -40,19 +40,19 @@ with `WORKSPACE_REQUIRED`; do not switch the shared active workspace.
|
|
|
40
40
|
For a real refill run:
|
|
41
41
|
|
|
42
42
|
```text
|
|
43
|
-
|
|
43
|
+
refill_sends_v2({ workspaceId, intent:"auto", senderIds?, approvalMode? })
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
For read-only inspection:
|
|
47
47
|
|
|
48
48
|
```text
|
|
49
|
-
|
|
49
|
+
refill_sends_v2({ workspaceId, dryRun:true, intent:"auto", senderIds? })
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
To resume an in-progress run, pass the handle back exactly:
|
|
53
53
|
|
|
54
54
|
```text
|
|
55
|
-
|
|
55
|
+
refill_sends_v2({ workspaceId, runId, fence })
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
If a stale handle loses the lease, the tool reports the holder status and the
|