@vruum/skills 0.6.51 → 0.6.53

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vruum",
3
- "version": "0.6.51",
3
+ "version": "0.6.53",
4
4
  "description": "Vruum AI skills + remote MCP server for B2B GTM teams. Slash commands for outreach triage, engagement triage, pipeline filling, prospect enrichment, and reply diagnosis, paired with the full Vruum MCP tool surface over OAuth 2.1.",
5
5
  "author": {
6
6
  "name": "Vruum AI",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vruum",
3
- "version": "0.6.51",
3
+ "version": "0.6.53",
4
4
  "description": "Vruum AI skills + remote MCP server for B2B GTM teams. Skills for outreach triage, engagement triage, pipeline filling, prospect enrichment, and reply diagnosis, paired with the full Vruum MCP tool surface over OAuth 2.1.",
5
5
  "author": {
6
6
  "name": "Vruum AI",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vruum/skills",
3
- "version": "0.6.51",
3
+ "version": "0.6.53",
4
4
  "description": "Vruum AI skills for Claude Code, Claude Desktop, Codex CLI, and any AI assistant with a skill directory. Slash commands for outreach triage, engagement triage, pipeline filling, prospect enrichment, and reply diagnosis. Pairs with the Vruum MCP server at https://api.vruum.ai/mcp.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -41,5 +41,5 @@
41
41
  "outreach",
42
42
  "gtm"
43
43
  ],
44
- "contentHash": "7b005a0d67d55681a74103c681916d07dbaebfc7b86107220ac0f22d7db0a0b9"
44
+ "contentHash": "f389e0800d9818f7b400b8032d3038ee34e512e077463f4ef1ddeb2020c3b1cc"
45
45
  }
@@ -52,6 +52,27 @@ Two paths — ask which:
52
52
  - **Reuse messaging that works** (default when they name an existing campaign): `manage_campaign` action=clone id=<existing campaign uuid> payload={name: "<new name>"}. Cloning carries the messaging structure, tone, and CTA configuration. Find the source campaign with `search` type="campaigns" if you only have its name.
53
53
  - **Fresh**: `manage_campaign` action=create payload={name, ...} — then offer to set tone/cadence via action=update once created.
54
54
 
55
+ After creation, call `fetch` with `type=settings subtype=channel_status` and
56
+ resolve the campaign's selected sender before assignment or launch:
57
+
58
+ - For email, list every `channels.email.accounts[]` row whose `user_id` matches
59
+ the selected sender. This is the campaign's configured mailbox pool. Treat
60
+ only rows with `eligible=true` as the live rotation pool, and show each
61
+ ineligible row's `eligibility_reason`. Do not describe one mailbox as the
62
+ fixed sender for every new prospect; first sends rotate across eligible rows.
63
+ - For LinkedIn, match `channels.linkedin_accounts[]` by `user_id` and require
64
+ `connected=true` for every LinkedIn action the sequence can select.
65
+ - If the sequence needs email and the selected sender has no mailbox with
66
+ `eligible=true`, stop with `state: "paused"`, code
67
+ `sender_channel_unavailable`. Do the same for a required LinkedIn route with
68
+ no connected LinkedIn account.
69
+ - State the identity rule: after the first email send, every email follow-up and
70
+ reply stays on that mailbox. An unavailable thread-owner mailbox holds the
71
+ action; Vruum never substitutes another email identity.
72
+
73
+ Do not silently add a channel because the sender has it connected. The authored
74
+ touch sequence remains the campaign's channel policy.
75
+
55
76
  ### Exact wording: touch templates (optional)
56
77
 
57
78
  If the seller wants the SAME proven email/message every time (instead of per-person AI drafting), set a **template** on the touch: `manage_campaign` action=update id=<campaign uuid> with the full `touch_sequence` where that step gains `{"template": {"subject": "...", "body": "..."}}`. Rules:
@@ -73,6 +94,16 @@ Show the seller a launch summary before anything sends:
73
94
  - Campaign name, source of messaging (cloned from X / fresh)
74
95
  - Cohort size and criteria
75
96
  - Channels, cadence, and maximum touches (from the campaign config). Enrollment schedules the first action immediately; spacing between later touches must already be represented in the campaign cadence.
97
+ - Selected sender and the email inboxes in that sender's campaign pool
98
+ - Any required sender channel that is disconnected or missing
99
+ - Reply behavior: a human reply permanently pauses every active enrollment for
100
+ that prospect and queues a response on the channel that received the reply
101
+ - Email identity behavior: new conversations rotate; established conversations
102
+ and email replies remain pinned to their original inbox
103
+
104
+ Refresh `fetch type=settings subtype=channel_status` immediately before asking
105
+ for launch confirmation. Do not trust the Step 3 snapshot because a connection
106
+ can change while the seller reviews the campaign.
76
107
 
77
108
  Then ask explicitly: "Launch outreach to these N people?" Only after a clear yes, call `manage_outreach` action=start id=[person uuids] (native bulk; payload optional `{max_touches, allowed_channels}`). Do not pass `start_immediately`; the MCP intentionally ignores it.
78
109
 
@@ -28,11 +28,15 @@ This is an analyst's job, not a batch import. The attribution step (which person
28
28
  - **Set** → the window is everything *after* that date.
29
29
  - **`null`** (no meeting logged yet — first run) → **ask the operator for a seed date** ("Ingest meetings since when? (default: last 30 days)"). Never silently default to the whole archive.
30
30
 
31
- 2. **Find candidates.** `search` type=kb with `filters={query: "meeting notes transcript live notes", include_content: false}`. Connector results carry `source_kind='connector'`, the meeting date in `modified_at`, a Drive `url`, and predictable filename shapes:
31
+ 2. **Find candidates — deterministic recency listing, NOT a keyword search.** `search` type=kb with `filters={doc_type: "connector", modified_after: "<watermark or seed date, ISO-8601>", include_content: false}` and **no `query`**. This returns every synced connector document modified after the watermark, newest first (up to 100). Connector results carry `source_kind='connector'`, the meeting date in `modified_at`, a Drive `url`, and predictable filename shapes:
32
32
  - **Gemini:** `… - Notes by Gemini`, `… - Transcript`, `… - Live Notes`
33
33
  - **Read.ai:** `… - Read Meeting Report`, `… Smart Notes`
34
34
 
35
- 3. **Apply the window drop everything at/before the watermark** (or the seed date). The Drive's historical archive is intentionally left KB-searchable-only, NOT re-ingested into the CRM. Logging an old meeting (and minting "follow up next week" tasks from a meeting that happened a year ago) is noise.
35
+ > **Never use a keyword query for this step.** A query (e.g. "meeting notes transcript live notes") is a relevance-ranked top-N sample over the whole archive on a Drive with years of old transcripts, recent meetings routinely fall below the relevance cutoff and the run wrongly concludes there is nothing new. Keyword search is fine later for looking things up; candidate discovery must be the `modified_after` listing.
36
+
37
+ 3. **Keep only the meeting artifacts.** The listing is every synced doc in the window, so drop non-meeting files (specs, sheets, decks) by the filename shapes above and obvious content. The Drive's historical archive is intentionally left KB-searchable-only, NOT re-ingested into the CRM. Logging an old meeting (and minting "follow up next week" tasks from a meeting that happened a year ago) is noise.
38
+
39
+ > **The window field is Drive *modified* time, not the meeting time.** They usually track each other, but an OLD transcript someone re-edits re-enters the window looking "new" — check the meeting date in the title/content, and the Step 5 idempotency marker catches anything already logged. If the listing returns exactly 100 documents, the window overflowed and the OLDEST part was cut (results are newest-first) — tell the user and pull the remainder via the Drive MCP alternative below; a narrower window can NOT recover it (the filter is a lower bound only).
36
40
 
37
41
  4. Present the surviving candidates as a short list: `name · meeting date · one-line summary`. **If none are newer than the watermark, say so and stop** — there are no new meetings to ingest.
38
42