@sellable/mcp 0.1.545 → 0.1.546

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.
@@ -8019,6 +8019,7 @@ export declare const allTools: ({
8019
8019
  };
8020
8020
  tableId?: undefined;
8021
8021
  template?: undefined;
8022
+ templateRef?: undefined;
8022
8023
  confirmed?: undefined;
8023
8024
  campaignId?: undefined;
8024
8025
  currentStep?: undefined;
@@ -8039,6 +8040,11 @@ export declare const allTools: ({
8039
8040
  type: string;
8040
8041
  description: string;
8041
8042
  };
8043
+ templateRef: {
8044
+ type: string;
8045
+ enum: string[];
8046
+ description: string;
8047
+ };
8042
8048
  confirmed: {
8043
8049
  type: string;
8044
8050
  description: string;
@@ -8078,6 +8084,7 @@ export declare const allTools: ({
8078
8084
  sequenceActions?: undefined;
8079
8085
  tableId?: undefined;
8080
8086
  template?: undefined;
8087
+ templateRef?: undefined;
8081
8088
  };
8082
8089
  required: string[];
8083
8090
  };
@@ -19,7 +19,8 @@ export type CreateWorkflowTableResponse = {
19
19
  };
20
20
  export type AttachSequenceInput = {
21
21
  tableId: string;
22
- template: Record<string, unknown>;
22
+ template?: Record<string, unknown>;
23
+ templateRef?: "connection_only";
23
24
  confirmed?: boolean;
24
25
  };
25
26
  export type AttachSequenceResponse = {
@@ -74,6 +75,7 @@ export declare const sequencerToolDefinitions: ({
74
75
  };
75
76
  tableId?: undefined;
76
77
  template?: undefined;
78
+ templateRef?: undefined;
77
79
  confirmed?: undefined;
78
80
  campaignId?: undefined;
79
81
  currentStep?: undefined;
@@ -94,6 +96,11 @@ export declare const sequencerToolDefinitions: ({
94
96
  type: string;
95
97
  description: string;
96
98
  };
99
+ templateRef: {
100
+ type: string;
101
+ enum: string[];
102
+ description: string;
103
+ };
97
104
  confirmed: {
98
105
  type: string;
99
106
  description: string;
@@ -133,6 +140,7 @@ export declare const sequencerToolDefinitions: ({
133
140
  sequenceActions?: undefined;
134
141
  tableId?: undefined;
135
142
  template?: undefined;
143
+ templateRef?: undefined;
136
144
  };
137
145
  required: string[];
138
146
  };
@@ -53,12 +53,17 @@ export const sequencerToolDefinitions = [
53
53
  type: "object",
54
54
  description: "Sequence template object with version, entryNodeId, nodes, and branches",
55
55
  },
56
+ templateRef: {
57
+ type: "string",
58
+ enum: ["connection_only"],
59
+ description: "Optional backend-owned known template reference. Use connection_only for invite-only evergreen setup without duplicating app template JSON in MCP.",
60
+ },
56
61
  confirmed: {
57
62
  type: "boolean",
58
63
  description: "Set true to overwrite existing sequence columns if the table already has them",
59
64
  },
60
65
  },
61
- required: ["tableId", "template"],
66
+ required: ["tableId"],
62
67
  },
63
68
  },
64
69
  {
@@ -107,31 +112,39 @@ export async function attachSequence(input) {
107
112
  const api = getApi();
108
113
  const template = input.template;
109
114
  const preValidationErrors = [];
110
- if (!Array.isArray(template.nodes) || template.nodes.length === 0) {
111
- preValidationErrors.push("Template must have a non-empty 'nodes' array.");
112
- }
113
- if (typeof template.entryNodeId !== "string" ||
114
- template.entryNodeId.trim().length === 0) {
115
- preValidationErrors.push("Template must have an 'entryNodeId' string.");
115
+ if (input.template && input.templateRef) {
116
+ throw new Error("INVALID_TEMPLATE: Pass either template or templateRef, not both.");
116
117
  }
117
- if (template.version !== 2) {
118
- preValidationErrors.push("Template version must be 2.");
118
+ if (!input.template && !input.templateRef) {
119
+ throw new Error("INVALID_TEMPLATE: Pass template or templateRef.");
119
120
  }
120
- if (Array.isArray(template.nodes) &&
121
- typeof template.entryNodeId === "string") {
122
- const nodeIds = new Set(template.nodes
123
- .map((node) => node && typeof node === "object"
124
- ? node.id
125
- : null)
126
- .filter((nodeId) => typeof nodeId === "string"));
127
- if (template.entryNodeId && !nodeIds.has(template.entryNodeId)) {
128
- preValidationErrors.push(`entryNodeId "${template.entryNodeId}" does not match any node id. Available node ids: ${Array.from(nodeIds).join(", ")}`);
121
+ if (input.template) {
122
+ if (!Array.isArray(template.nodes) || template.nodes.length === 0) {
123
+ preValidationErrors.push("Template must have a non-empty 'nodes' array.");
124
+ }
125
+ if (typeof template.entryNodeId !== "string" ||
126
+ template.entryNodeId.trim().length === 0) {
127
+ preValidationErrors.push("Template must have an 'entryNodeId' string.");
128
+ }
129
+ if (template.version !== 2) {
130
+ preValidationErrors.push("Template version must be 2.");
131
+ }
132
+ if (Array.isArray(template.nodes) &&
133
+ typeof template.entryNodeId === "string") {
134
+ const nodeIds = new Set(template.nodes
135
+ .map((node) => node && typeof node === "object"
136
+ ? node.id
137
+ : null)
138
+ .filter((nodeId) => typeof nodeId === "string"));
139
+ if (template.entryNodeId && !nodeIds.has(template.entryNodeId)) {
140
+ preValidationErrors.push(`entryNodeId "${template.entryNodeId}" does not match any node id. Available node ids: ${Array.from(nodeIds).join(", ")}`);
141
+ }
142
+ }
143
+ if (preValidationErrors.length > 0) {
144
+ throw new Error("INVALID_TEMPLATE: Template has structural issues:\n" +
145
+ preValidationErrors.map((issue) => ` - ${issue}`).join("\n") +
146
+ "\n\nFix these issues and retry.");
129
147
  }
130
- }
131
- if (preValidationErrors.length > 0) {
132
- throw new Error("INVALID_TEMPLATE: Template has structural issues:\n" +
133
- preValidationErrors.map((issue) => ` - ${issue}`).join("\n") +
134
- "\n\nFix these issues and retry.");
135
148
  }
136
149
  // Campaign-backed tables route to the campaigns endpoint so the MCP
137
150
  // tool persists the sequence to the same place the UI does
@@ -155,7 +168,8 @@ export async function attachSequence(input) {
155
168
  : `/api/v3/workflow-tables/${input.tableId}/sequence`;
156
169
  try {
157
170
  return await api.put(endpoint, {
158
- template: input.template,
171
+ ...(input.template ? { template: input.template } : {}),
172
+ ...(input.templateRef ? { templateRef: input.templateRef } : {}),
159
173
  confirmed: input.confirmed,
160
174
  });
161
175
  }
@@ -1,4 +1,5 @@
1
1
  type SetupEvergreenCampaignsInput = {
2
+ workspaceId?: string;
2
3
  mode?: "plan" | "verify";
3
4
  depth?: "structure_only" | "customer_visible";
4
5
  handoffMode?: "create_campaign_goals";
@@ -15,6 +16,9 @@ type SetupEvergreenCampaignsInput = {
15
16
  planRevision?: string;
16
17
  selectedActionIds?: string[];
17
18
  receipts?: Array<Record<string, unknown>>;
19
+ campaignSequenceOptions?: {
20
+ mode: "connection_only";
21
+ };
18
22
  };
19
23
  export declare const setupEvergreenCampaignsToolDefinitions: {
20
24
  name: string;
@@ -27,6 +31,23 @@ export declare const setupEvergreenCampaignsToolDefinitions: {
27
31
  enum: string[];
28
32
  description: string;
29
33
  };
34
+ workspaceId: {
35
+ type: string;
36
+ description: string;
37
+ };
38
+ campaignSequenceOptions: {
39
+ type: string;
40
+ properties: {
41
+ mode: {
42
+ type: string;
43
+ enum: string[];
44
+ description: string;
45
+ };
46
+ };
47
+ required: string[];
48
+ additionalProperties: boolean;
49
+ description: string;
50
+ };
30
51
  depth: {
31
52
  type: string;
32
53
  enum: string[];
@@ -1,7 +1,7 @@
1
1
  import { getApi } from "../api.js";
2
- async function postSetupEvergreenCampaigns(body) {
2
+ async function postSetupEvergreenCampaigns(body, workspaceId) {
3
3
  const api = getApi();
4
- return api.post("/api/v3/mcp/setup-evergreen-campaigns", body);
4
+ return api.post("/api/v3/mcp/setup-evergreen-campaigns", body, workspaceId ? { workspaceId } : undefined);
5
5
  }
6
6
  export const setupEvergreenCampaignsToolDefinitions = [
7
7
  {
@@ -15,6 +15,23 @@ export const setupEvergreenCampaignsToolDefinitions = [
15
15
  enum: ["plan", "verify"],
16
16
  description: 'Defaults to "plan". Verify only validates worker receipts.',
17
17
  },
18
+ workspaceId: {
19
+ type: "string",
20
+ description: "Optional explicit workspace id. Required for connection-only evergreen setup; it is also sent as the request workspace so concurrent threads cannot drift to another active workspace.",
21
+ },
22
+ campaignSequenceOptions: {
23
+ type: "object",
24
+ properties: {
25
+ mode: {
26
+ type: "string",
27
+ enum: ["connection_only"],
28
+ description: "Optional non-default sequence policy. connection_only means attach the canonical invite-only template and verify exactly send_invite, with no DM, InMail, View Profile, follow-up, launch, or send side effects.",
29
+ },
30
+ },
31
+ required: ["mode"],
32
+ additionalProperties: false,
33
+ description: "Optional non-default evergreen sequence policy. Omit to keep the standard tier-recommended Premium/Sales Nav behavior.",
34
+ },
18
35
  depth: {
19
36
  type: "string",
20
37
  enum: ["structure_only", "customer_visible"],
@@ -90,10 +107,12 @@ export const setupEvergreenCampaignsToolDefinitions = [
90
107
  ];
91
108
  export function setupEvergreenCampaigns(input) {
92
109
  return postSetupEvergreenCampaigns({
110
+ workspaceId: input.workspaceId,
93
111
  mode: input.mode,
94
112
  yolo: input.mode === "verify" ? undefined : input.yolo,
95
113
  depth: input.depth,
96
114
  handoffMode: input.mode === "verify" ? undefined : input.handoffMode,
115
+ campaignSequenceOptions: input.campaignSequenceOptions,
97
116
  allConnectedSenders: input.allConnectedSenders,
98
117
  selectedSenderIds: input.selectedSenderIds,
99
118
  postEngagerSenderIds: input.postEngagerSenderIds,
@@ -102,5 +121,5 @@ export function setupEvergreenCampaigns(input) {
102
121
  planRevision: input.planRevision,
103
122
  selectedActionIds: input.selectedActionIds,
104
123
  receipts: input.receipts,
105
- });
124
+ }, input.workspaceId);
106
125
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.545",
3
+ "version": "0.1.546",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code, Codex, and Hermes campaign workflows",
6
6
  "main": "dist/index.js",
@@ -59,6 +59,11 @@ The tail MUST verify:
59
59
 
60
60
  - `attach_recommended_sequence` is the only way to pick a template in
61
61
  the autonomous tail. Do NOT hand-wire a sequence at Step 16.
62
+ - Exception: when the parent `$sellable:create-evergreen-campaigns` plan
63
+ explicitly carries `campaignSequenceOptions:{ mode:"connection_only" }`,
64
+ do not call `attach_recommended_sequence`. Use the backend-owned
65
+ `attach_sequence({ tableId, templateRef:"connection_only" })` path and prove
66
+ `sequenceReceipt.actionTypes:["send_invite"]`.
62
67
  - Tier mismatch at attach time is an escalation, NOT a silent fallback.
63
68
  - A Standard sender MUST NOT be attached to an INMAIL_OPEN template.
64
69
  This would produce sends that fail at Unipile with `not_authorized`.
@@ -134,6 +134,18 @@ run without user input, or similar, run in **automation mode**:
134
134
  exactly one quality-valid route-proof row when needed, and attach the
135
135
  recommended sequence, but it still must not launch campaigns, schedule
136
136
  sends, send messages, or spend paid InMail.
137
+ - **Connection-only evergreen completion is optional and non-default.** Use it
138
+ only when the prompt explicitly says connection-only, invite-only,
139
+ connection request only, no DMs, or no follow-ups. Pass the typed option
140
+ `campaignSequenceOptions:{ mode:"connection_only" }` plus an explicit
141
+ `workspaceId` to `setup_evergreen_campaigns`. Omit
142
+ `campaignSequenceOptions` for the standard tier-recommended Premium,
143
+ Sales Nav, Recruiter, and paid InMail behavior.
144
+ Connection-only completion still creates/reuses the same evergreen lanes,
145
+ source rows, and paused/unlaunched review state, but it attaches only the
146
+ canonical invite template. It does not require Message Drafting, generated
147
+ messages, route-proof approval, first DM, InMail, View Profile fallback,
148
+ follow-up branch, `currentStep:"send"`, launch, scheduling, or sends.
137
149
 
138
150
  If the invoking prompt explicitly asks for interactive message polish or sample
139
151
  proof, run in **interactive polish mode** and use the confirmation/sample steps
@@ -720,6 +732,9 @@ not a parent-thread summary. The receipt must include:
720
732
  creation, preserve that original packet only in a separate `parentLanePacket`
721
733
  object; do not leave `setupPlanCall.campaignId:null` or
722
734
  `setupPlanCall.tableId:null`.
735
+ If the parent plan used connection-only, the receipt must also include
736
+ `setupPlanCall.campaignSequenceOptions:{ "mode":"connection_only" }` or
737
+ `setupPlanCall.sequencePolicy.mode:"connection_only"`.
723
738
  Short form: For create lanes, `setupPlanCall.campaignId` and `setupPlanCall.tableId` must be the actual created campaign/table ids.
724
739
  Short form: Do not leave `setupPlanCall.campaignId:null` or `setupPlanCall.tableId:null`.
725
740
  - `createCampaignWorkflowReceipt`: proof the worker loaded the actual installed
@@ -810,21 +825,39 @@ not a parent-thread summary. The receipt must include:
810
825
  them into canonical `promptLoadedToHasMoreFalse`, `requiredAssetsLoaded`,
811
826
  `validationLoaded`, `reviewBatchRowHash`, and
812
827
  `messageDraftRecommendation`.
828
+ Connection-only lanes are the exception: do not include
829
+ `messageDraftingReceipt` or run generated-message prep unless the operator
830
+ separately asked for message copy. The parent verifier expects no message
831
+ proof for connection-only lanes.
813
832
  - `reviewBatchReceipt`: review-batch row ids/hash, generated row count,
814
833
  quality-valid route-proof row id when approved, and proof that no broad
815
834
  approve-all occurred.
835
+ Connection-only lanes are the exception: do not approve a route-proof row and
836
+ do not include a required review-batch receipt.
816
837
  - `sequenceReceipt`: exact current workflowTableId, recommended non-paid
817
838
  sequence attach/precheck result, and readback showing `hasSequence:true` when
818
839
  completion is claimed. If the tool output uses
819
840
  `attachRecommendedSequenceResult.actionTypes` or
820
841
  `nonPaidRecommendedSequence`, copy them to canonical `actionTypes` and
821
842
  `nonPaid`.
843
+ For connection-only lanes, do not call `attach_recommended_sequence`. Attach
844
+ with `attach_sequence({ tableId, templateRef:"connection_only" })`, then
845
+ include exact current-template proof:
846
+ `sequenceReceipt.hasSequence:true`,
847
+ `sequenceReceipt.actionTypes:["send_invite"]`, and
848
+ `sequenceReceipt.nonPaid:true`. Receipts that only say
849
+ `tool:"attach_recommended_sequence"` or include `send_dm`,
850
+ `send_inmail_open`, `send_inmail_closed`, or `view_profile` are failing
851
+ connection-only receipts.
822
852
  - final paused-send proof: if the current campaign table is `DRAFT` after the
823
853
  sequence is attached, call the product `pause_campaign({ campaignId })`
824
854
  endpoint/tool to put the unlaunched campaign into `PAUSED` review state, then
825
855
  reread the campaign/table. Do not raw-write `campaignStatus`, do not start or
826
856
  launch, and do not schedule/send. Completion requires reread proof of
827
- `currentStep:"send"` and `campaignStatus:"PAUSED"`. If the raw output nests
857
+ `currentStep:"send"` and `campaignStatus:"PAUSED"` for standard
858
+ customer-visible lanes. Connection-only lanes may finish at a paused
859
+ unlaunched review step such as `currentStep:"review"` as long as the exact
860
+ invite-only sequence proof and source-row proof pass. If the raw output nests
828
861
  this in `finalCampaignRead` or `finalTableRead`, copy it to canonical
829
862
  `finalPausedSendProof.currentStep` and
830
863
  `finalPausedSendProof.campaignStatus`.
@@ -1088,9 +1121,14 @@ plain row generation. The lane worker must inline the same
1088
1121
  approvedGeneratedMessageCount exactly 1. Do not report completion with 2+
1089
1122
  approved rows.
1090
1123
  Approval shorthand: Do not report completion with 2+ approved rows.
1091
- 8. Continue to `attach_recommended_sequence({ campaignId, currentStep:"send" })`
1092
- and, if the campaign is still `DRAFT`, `pause_campaign({ campaignId })`.
1093
- Reread the campaign/table before claiming completion.
1124
+ 8. Standard mode: continue to
1125
+ `attach_recommended_sequence({ campaignId, currentStep:"send" })` and, if
1126
+ the campaign is still `DRAFT`, `pause_campaign({ campaignId })`. Reread the
1127
+ campaign/table before claiming completion.
1128
+ Connection-only mode: skip Message Drafting and route-proof approval, call
1129
+ `attach_sequence({ tableId, templateRef:"connection_only" })`, prove
1130
+ `sequenceReceipt.actionTypes:["send_invite"]`, and pause/reread without
1131
+ launching or sending.
1094
1132
 
1095
1133
  That packaged worker path must return `messageDraftingReceipt.statusSource:
1096
1134
  "packaged-generate-messages-worker"`. It is accepted only when the receipt
@@ -1515,11 +1553,14 @@ Message, and verify current-revision sample messages before final completion.
1515
1553
  - DM lanes: add a `Delivery format:` line — either `multiline (each paragraph sends as its own DM message)` or `single message`. When multiline, the template's blank-line paragraphs ARE the message boundaries — write each one as a standalone typed message.
1516
1554
  - **InMail lanes can never be multiline**: an InMail is one message and the recipient must reply before anything else can be sent. InMail-bound templates must read as one cohesive message — declare `Delivery format: single message (InMail — no follow-up until reply)` and never structure the copy to depend on multi-message pacing.
1517
1555
 
1518
- - The sequence is auto-selected by sender tier; do not hand-author sequence
1556
+ - In standard mode, the sequence is auto-selected by sender tier; do not hand-author sequence
1519
1557
  templates here. Sales Nav/Recruiter senders may receive the unified Sales
1520
1558
  Nav cascade through `attach_recommended_sequence`; attaching it does not
1521
1559
  spend paid InMail credits by itself. Do not substitute the manual Paid
1522
1560
  InMail Campaign template.
1561
+ For explicit connection-only evergreen lanes only, use the backend-owned
1562
+ `attach_sequence({ tableId, templateRef:"connection_only" })` path and do
1563
+ not call `attach_recommended_sequence`.
1523
1564
  3. **Customer-Visible Completion Contract**: a named evergreen lane that appears
1524
1565
  as a campaign card or campaign-backed table is not done when the shell exists.
1525
1566
  It is done only when the customer can open the campaign and land on final
@@ -1543,7 +1584,7 @@ Message, and verify current-revision sample messages before final completion.
1543
1584
  evergreen setup. Do not leave customer-visible campaigns at
1544
1585
  `filter-choice`, `filter-rules`, or `apply-icp-rubric` and report success.
1545
1586
  Do not proceed to Message Drafting until saved filters are applied.
1546
- - Message Drafting has run from the current campaign/table basis, using the
1587
+ - In standard mode, Message Drafting has run from the current campaign/table basis, using the
1547
1588
  create-campaign message prompt/assets and validation gate. Updating
1548
1589
  `currentStep:"messages"` is not proof. Parent-thread handwritten copy is
1549
1590
  not a substitute. The proof receipt must show
@@ -1584,6 +1625,9 @@ Message, and verify current-revision sample messages before final completion.
1584
1625
  Fallback samples must still reject source/conversation hedges such as
1585
1626
  `"hope this is relevant"`, `"might be interested"`, or `"saw you in a few
1586
1627
  conversations"`.
1628
+ For explicit connection-only lanes, this whole Message Drafting and sample
1629
+ proof block is not required and must not be faked with parent-written
1630
+ messages.
1587
1631
  - The first review batch exists and at least 3 review rows have generated
1588
1632
  messages from the approved brief. If fewer than 3 usable rows exist, report
1589
1633
  the actual count and why.
@@ -1596,7 +1640,7 @@ Message, and verify current-revision sample messages before final completion.
1596
1640
  completion, approve exactly one quality-valid generated row. If one or more
1597
1641
  rows are already approved, do not add more approvals during evergreen
1598
1642
  completion. Never broad approve all rows.
1599
- - The recommended tier-aware sequence is attached to the current campaign
1643
+ - In standard mode, the recommended tier-aware sequence is attached to the current campaign
1600
1644
  table, and the watched campaign is on Send. Use
1601
1645
  `attach_recommended_sequence({ campaignId, currentStep:"send" })` when a
1602
1646
  safe attach is needed. After `confirm_lead_list` or any source-list copy,
@@ -1611,6 +1655,10 @@ Message, and verify current-revision sample messages before final completion.
1611
1655
  manual Paid InMail Campaign, and never attach/replace sequence outside the
1612
1656
  current table unless the current lane packet explicitly allowed sequence
1613
1657
  repair.
1658
+ For explicit connection-only lanes, the current campaign table must have
1659
+ exactly the canonical invite-only sequence:
1660
+ `sequenceReceipt.actionTypes:["send_invite"]`. Any DM, InMail, or View
1661
+ Profile action means the lane is not complete.
1614
1662
  - If the current campaign table is still `DRAFT` after sequence/readiness
1615
1663
  proof, call `pause_campaign({ campaignId })` and reread. `pause_campaign`
1616
1664
  is the product-native review-state transition; it is not a launch and does
@@ -196,6 +196,11 @@ rather than asking which campaign class to fill. If a stale target plan selects
196
196
  planner before mutation.
197
197
  Short form: trust the target plan's inferred lane when it is a connection invite,
198
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.
199
204
 
200
205
  Structured planner packet:
201
206
 
@@ -62,6 +62,11 @@ for lease expiry; never guess a fence.
62
62
  The default `intent:"auto"` inspects `managed_waterfall`,
63
63
  `dashboard_evergreen`, and `active_campaign` lane sources. Report the lane
64
64
  source and lane chain as proof for every selected sender.
65
+ Connection-only evergreen lanes are invite-only refill targets. When the packet
66
+ or campaign proof shows exactly `["send_invite"]`, report and execute only
67
+ `selectedLane:"send_invite"` work; do not infer DM, InMail, Sales Nav cascade,
68
+ paid-credit refresh, message generation, follow-up, sequence mutation,
69
+ launch/start beyond packet authority, scheduler writes, or direct sends.
65
70
 
66
71
  If membership blocks a workspace read, report the structured
67
72
  `workspace_access` blocker instead of retrying auth or switching workspaces.
@@ -61,6 +61,13 @@ the repair rung, such as re-run errored enrichment/message cells
61
61
  (`start_campaign`). The loop bounds and refuses repair loops; it never invents
62
62
  a fix list.
63
63
 
64
+ Connection-only evergreen packets are invite-only. If the selected lane or
65
+ campaign proof is exactly `["send_invite"]`, the workflow may refill only
66
+ `selectedLane:"send_invite"` capacity. Do not treat that lane as a DM, InMail,
67
+ Sales Nav cascade, paid-credit refresh, generated-message requirement,
68
+ follow-up branch, sequence-repair task, scheduler write, launch/send, or
69
+ provider-family continuation.
70
+
64
71
  Use plain-language labels first and tokens second, for example "copy leads
65
72
  already found into the campaign table (`reconcile_source_copy`)".
66
73
 
@@ -52,6 +52,7 @@
52
52
  "awaiting scheduler is not an end state; window-closed reports name remaining-ready, expected pickup time, and resume handle",
53
53
  "honest-rubric-fail means a human updates the rubric or changes lead source",
54
54
  "source replenishment beyond same-source-automatic is a scoped create-campaign handoff, never refill-owned provider search",
55
+ "connection-only evergreen lanes with exact [\"send_invite\"] proof are invite-only refill capacity; never infer DM, InMail, Sales Nav cascade, paid-credit refresh, message generation, follow-up, sequence mutation, scheduler writes, launch, or send work from them",
55
56
  "no campaign creation, provider-family switch, threshold lowering, scheduler writes, sends, archives, deletes, or brief/filter/message/sequence/sender mutation without a separate approval packet"
56
57
  ],
57
58
  "requiredBootstrap": [
@@ -0,0 +1,9 @@
1
+ {
2
+ "parallelMode": "wide",
3
+ "agentCount": 6,
4
+ "maxToolCallsPerAgent": 2,
5
+ "senderMaxAgents": 2,
6
+ "senderMaxToolCallsPerAgent": 3,
7
+ "progressMode": true,
8
+ "debugMode": true
9
+ }