@vruum/skills 0.6.15 → 0.6.17
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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/bin/vruum-skills-update-check +24 -4
- package/package.json +2 -2
- package/skills/csv-pipeline-fill/SKILL.md +2 -2
- package/skills/diagnose-reply/SKILL.md +8 -8
- package/skills/engagement-triage/SKILL.md +1 -1
- package/skills/engagement-triage/references/engagement-subagent-instructions.md +1 -1
- package/skills/expansion-fill/SKILL.md +1 -1
- package/skills/outreach-triage/SKILL.md +2 -2
- package/skills/outreach-triage/references/quality-standards.md +11 -11
- package/skills/outreach-triage/references/subagent-instructions.md +5 -5
- package/skills/pipeline-fill/RESEARCH-ENGINE.md +20 -20
- package/skills/pipeline-fill/SKILL.md +21 -21
- package/skills/sales-nav-deep-fill/SKILL.md +4 -4
- package/skills/vruum-skills-upgrade/SKILL.md +5 -2
- package/skills/winback-fill/SKILL.md +1 -1
- package/skills/yc-pipeline-fill/SKILL.md +5 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vruum",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.17",
|
|
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.
|
|
3
|
+
"version": "0.6.17",
|
|
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",
|
|
@@ -21,7 +21,9 @@ CONFIG_FILE="$STATE_DIR/config.yaml"
|
|
|
21
21
|
REMOTE_URL="${VRUUM_REMOTE_URL:-https://registry.npmjs.org/@vruum/skills/latest}"
|
|
22
22
|
|
|
23
23
|
# Force flag busts cache + snooze (used by /vruum-skills-upgrade directly)
|
|
24
|
+
FORCE=0
|
|
24
25
|
if [ "${1:-}" = "--force" ]; then
|
|
26
|
+
FORCE=1
|
|
25
27
|
rm -f "$CACHE_FILE" "$SNOOZE_FILE"
|
|
26
28
|
fi
|
|
27
29
|
|
|
@@ -75,6 +77,7 @@ if [ -f "$CACHE_FILE" ]; then
|
|
|
75
77
|
case "$CACHED" in
|
|
76
78
|
UP_TO_DATE*) TTL=60 ;;
|
|
77
79
|
UPGRADE_AVAILABLE*) TTL=720 ;;
|
|
80
|
+
CHECK_FAILED*) TTL=30 ;;
|
|
78
81
|
*) TTL=0 ;;
|
|
79
82
|
esac
|
|
80
83
|
STALE=$(find "$CACHE_FILE" -mmin +"$TTL" 2>/dev/null || true)
|
|
@@ -93,6 +96,12 @@ if [ -f "$CACHE_FILE" ]; then
|
|
|
93
96
|
exit 0
|
|
94
97
|
fi
|
|
95
98
|
;;
|
|
99
|
+
CHECK_FAILED*)
|
|
100
|
+
# Recent fetch failure cached — stay quiet and do NOT imply "up to
|
|
101
|
+
# date". Retry once the short TTL expires. A --force run never reaches
|
|
102
|
+
# here (it cleared the cache above), so it always re-fetches.
|
|
103
|
+
exit 0
|
|
104
|
+
;;
|
|
96
105
|
esac
|
|
97
106
|
fi
|
|
98
107
|
fi
|
|
@@ -100,13 +109,24 @@ fi
|
|
|
100
109
|
# Step 5: slow path — fetch latest from npm registry.
|
|
101
110
|
mkdir -p "$STATE_DIR"
|
|
102
111
|
RESP="$(curl -fsSL --max-time 5 "$REMOTE_URL" 2>/dev/null || true)"
|
|
103
|
-
# Extract "version":"X.Y.Z" without jq.
|
|
104
|
-
|
|
112
|
+
# Extract "version":"X.Y.Z" without jq. The trailing `|| true` is load-bearing
|
|
113
|
+
# under `set -euo pipefail`: on a failed/empty fetch the grep matches nothing
|
|
114
|
+
# and (with pipefail) the pipeline exits non-zero, which would errexit the whole
|
|
115
|
+
# script mid-way — the original silent-failure path. Swallow it so REMOTE ends
|
|
116
|
+
# up empty and the unreachable-registry branch below handles it deliberately.
|
|
117
|
+
REMOTE="$(echo "$RESP" | grep -oE '"version"[[:space:]]*:[[:space:]]*"[^"]+"' | head -1 | sed -E 's/.*"([^"]+)"$/\1/' || true)"
|
|
105
118
|
REMOTE="$(echo "$REMOTE" | tr -d '[:space:]')"
|
|
106
119
|
|
|
107
|
-
#
|
|
120
|
+
# Registry unreachable or unparseable response. A failed fetch is NOT evidence
|
|
121
|
+
# the local version is current — caching UP_TO_DATE here is the false-positive
|
|
122
|
+
# that pinned a sandboxed client to a stale bundle: its forced check returned
|
|
123
|
+
# nothing, which /vruum-skills-upgrade reads as "already on latest". Cache a
|
|
124
|
+
# short-lived CHECK_FAILED marker so passive checks don't hammer the registry,
|
|
125
|
+
# but never claim current. A forced check surfaces the failure so the user
|
|
126
|
+
# knows it couldn't run (vs. a real up-to-date).
|
|
108
127
|
if ! echo "$REMOTE" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then
|
|
109
|
-
echo "
|
|
128
|
+
echo "CHECK_FAILED $LOCAL $(date +%s)" > "$CACHE_FILE"
|
|
129
|
+
if [ "$FORCE" = 1 ]; then echo "CHECK_FAILED $LOCAL"; fi
|
|
110
130
|
exit 0
|
|
111
131
|
fi
|
|
112
132
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vruum/skills",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.17",
|
|
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": {
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"outreach",
|
|
43
43
|
"gtm"
|
|
44
44
|
],
|
|
45
|
-
"contentHash": "
|
|
45
|
+
"contentHash": "ea6ebae97d7fd0f6f8ffe802a6634b495697627372def939359629ba6a0a0bee"
|
|
46
46
|
}
|
|
@@ -15,7 +15,7 @@ You are the CSV harness-mode source for `/pipeline-fill`. You read a CSV the ope
|
|
|
15
15
|
## Inputs
|
|
16
16
|
|
|
17
17
|
- `file_path`: absolute path to the CSV. If not provided, ask for it. Common locations: `~/Downloads/`, `.context/attachments/` in the workspace.
|
|
18
|
-
- `
|
|
18
|
+
- `campaign`: target campaign (single)
|
|
19
19
|
- `column_mapping` (optional): explicit `{header_name: canonical_field}` mapping if headers don't auto-resolve. Default: auto-detect.
|
|
20
20
|
|
|
21
21
|
## Workflow
|
|
@@ -97,7 +97,7 @@ Emit the canonical handoff prompt (defined in `pipeline-fill/RESEARCH-ENGINE.md`
|
|
|
97
97
|
```
|
|
98
98
|
Candidate list ready: {N} prospects from csv (after {dedup_count} dedup).
|
|
99
99
|
|
|
100
|
-
NEXT: invoke /pipeline-fill Step 3 onward (deep research → harness gate → save) with this list and
|
|
100
|
+
NEXT: invoke /pipeline-fill Step 3 onward (deep research → harness gate → save) with this list and campaign {campaign_id}.
|
|
101
101
|
|
|
102
102
|
Continue automatically? (y/n)
|
|
103
103
|
```
|
|
@@ -28,7 +28,7 @@ From the person_360 response, read the full conversation thread. Identify:
|
|
|
28
28
|
|
|
29
29
|
## Step 3: Diagnose
|
|
30
30
|
|
|
31
|
-
Call `get_performance_metrics` with `view='funnel'` and the
|
|
31
|
+
Call `get_performance_metrics` with `view='funnel'` and the campaign_id to get campaign-level reply rates by channel.
|
|
32
32
|
|
|
33
33
|
Synthesize a diagnosis:
|
|
34
34
|
|
|
@@ -37,13 +37,13 @@ Synthesize a diagnosis:
|
|
|
37
37
|
**The message that got the reply:** T3 via LinkedIn DM, 'workflow_pain' angle, referenced their recent job posting for DevOps engineer (specific signal), ended with a question about their current tooling.
|
|
38
38
|
|
|
39
39
|
**Why it likely worked:**
|
|
40
|
-
- Channel: LinkedIn DM has [X]% reply rate in this
|
|
41
|
-
- Angle: 'workflow_pain' converts at [X]% in this
|
|
40
|
+
- Channel: LinkedIn DM has [X]% reply rate in this campaign (vs [Y]% email)
|
|
41
|
+
- Angle: 'workflow_pain' converts at [X]% in this campaign ([Z]x above average)
|
|
42
42
|
- Signal: Referenced a specific, verifiable company signal (job posting)
|
|
43
43
|
- CTA: Question CTA has [X]x lift over statement CTAs
|
|
44
44
|
|
|
45
45
|
**What's different from the ghosted messages:**
|
|
46
|
-
- T1 and T2 used 'cost_replacement' angle (
|
|
46
|
+
- T1 and T2 used 'cost_replacement' angle (campaign average: [X]%)
|
|
47
47
|
- T1 had surface-level personalization (company name only)
|
|
48
48
|
- T2 had no question CTA
|
|
49
49
|
|
|
@@ -52,10 +52,10 @@ Synthesize a diagnosis:
|
|
|
52
52
|
## Step 4: Suggest action
|
|
53
53
|
|
|
54
54
|
**If positive reply** (interested, wants to learn more, asks a question):
|
|
55
|
-
- "This combination is worth repeating: [angle + specific signal + CTA style]. Note it in your
|
|
55
|
+
- "This combination is worth repeating: [angle + specific signal + CTA style]. Note it in your campaign's strategy so the next batch follows the same shape."
|
|
56
56
|
|
|
57
57
|
**If negative reply** (not interested, wrong person, bad timing):
|
|
58
|
-
- "This is the [N]th rejection using the '[angle]' strategy in this
|
|
58
|
+
- "This is the [N]th rejection using the '[angle]' strategy in this campaign. If the pattern holds, consider deprioritizing this angle for the campaign."
|
|
59
59
|
|
|
60
60
|
**If objection or question** (pricing, timing, skepticism):
|
|
61
61
|
- "This is a live conversation. The reply response draft should address [specific objection]. Check the outreach queue — there may be a draft pending."
|
|
@@ -64,5 +64,5 @@ Synthesize a diagnosis:
|
|
|
64
64
|
|
|
65
65
|
- This skill is diagnostic, not prescriptive. It explains what happened; acting on the pattern (deprioritizing an angle, repeating a winning combination) is a separate, deliberate decision.
|
|
66
66
|
- When the conversation has many touches, focus on the touch that triggered the reply, not the full sequence.
|
|
67
|
-
- Always compare against
|
|
68
|
-
- If `get_performance_metrics` doesn't have enough data for the
|
|
67
|
+
- Always compare against campaign averages to distinguish signal from noise. One data point doesn't make a pattern.
|
|
68
|
+
- If `get_performance_metrics` doesn't have enough data for the campaign, say so: "Not enough campaign data to compare against. This is a single data point."
|
|
@@ -194,7 +194,7 @@ After the first batch returns for any engagement type:
|
|
|
194
194
|
|
|
195
195
|
- **All reactions clean:** "First batch of reactions all approved. N more look similar — approve the rest?" Apply without more agents.
|
|
196
196
|
- **All comments have the same issue** (e.g., all too generic, all missing sender voice): Flag the pattern to the user. "First 8 comments are all generic 'great post' style — likely a prompt issue. Want me to edit them all with the same fix, or skip the batch?"
|
|
197
|
-
- **Systematic voice mismatch:** If comments consistently don't sound like the sender, flag it as a
|
|
197
|
+
- **Systematic voice mismatch:** If comments consistently don't sound like the sender, flag it as a campaign/prompt config issue rather than fixing each one individually.
|
|
198
198
|
|
|
199
199
|
### Step 8: Summary
|
|
200
200
|
|
|
@@ -21,7 +21,7 @@ Call `get_engagement_review` with your assigned `engagement_ids`, `content_lengt
|
|
|
21
21
|
- `polish_provenance.polished_floor.regressed` — true means the backend's floor rewrite was worse than first_draft and was reverted (signal that the rules are hard for this draft)
|
|
22
22
|
- `validator_failures` — structural failures recorded by the backend (e.g. `["banned_opener:Yep","no_specific_marker:0/1"]`). Treat as a checklist.
|
|
23
23
|
- `target_post_text` — what the prospect actually posted
|
|
24
|
-
- `person_id`, `person_name`, `person_title`, `match_score`, `
|
|
24
|
+
- `person_id`, `person_name`, `person_title`, `match_score`, `campaign_name` — person context
|
|
25
25
|
- `source` — `warming` / `nurture` / `marketing`
|
|
26
26
|
- `budget_status` — sender daily quota
|
|
27
27
|
- `schema_version` + `rules_version` — backward-compat signals
|
|
@@ -64,7 +64,7 @@ For each row, include a one-line "hook" — a specific recent observation from `
|
|
|
64
64
|
|
|
65
65
|
Step 6 — Hand off to outreach. Two options:
|
|
66
66
|
- **Option A (recommended)**: Approve the ranked list, then for each account: run `/pipeline-fill` with that prospect_list — same Sales Nav harness flow, just sourced from the expansion cohort instead of cold. Tag the resulting `outreach_plans.tag` with `bowtie_pilot:expansion` so success-tracking finds them.
|
|
67
|
-
- **Option B**: Direct `manage_outreach` action=start with an expansion-flavored
|
|
67
|
+
- **Option B**: Direct `manage_outreach` action=start with an expansion-flavored campaign (pre-create an `expansion_<your-tenant>` campaign with the right tone — formal, ROI-focused, no opener-hooks since the customer already knows you).
|
|
68
68
|
|
|
69
69
|
Step 7 — Success tracking (auto). When a calendar webhook fires a `meeting_booked` event on an outreach plan tagged `bowtie_pilot:expansion`, the webhook handler in `backend/app/domains/calendar/` auto-records the impact event, equivalent to:
|
|
70
70
|
```
|
|
@@ -11,7 +11,7 @@ You are an outreach queue orchestrator. Your job is to efficiently process pendi
|
|
|
11
11
|
|
|
12
12
|
## Why this skill exists
|
|
13
13
|
|
|
14
|
-
Reviewing outreach messages is context-expensive. Each message with full context (conversation thread,
|
|
14
|
+
Reviewing outreach messages is context-expensive. Each message with full context (conversation thread, campaign instructions, match analysis, company research) consumes significant tokens. This skill solves that by dispatching messages to independent subagents, each with their own context window, who do the deep review work and return compact summaries.
|
|
15
15
|
|
|
16
16
|
## Subagent architecture
|
|
17
17
|
|
|
@@ -116,7 +116,7 @@ Prospect: {person_name}, {title} at {company}
|
|
|
116
116
|
Message type: T{sequence_number} follow-up
|
|
117
117
|
|
|
118
118
|
Steps:
|
|
119
|
-
1. Call get_outreach_review with message_ids="{message_id}" and content_length="full" to get the current message, thread context,
|
|
119
|
+
1. Call get_outreach_review with message_ids="{message_id}" and content_length="full" to get the current message, thread context, campaign instructions, and match analysis.
|
|
120
120
|
2. Call fetch with type=person_research plus get_person_360 for this person to get everything we know.
|
|
121
121
|
3. Call fetch with type=company_research to understand the company's product, positioning, and what problems it solves.
|
|
122
122
|
4. Search the web for this prospect and their company to understand what they actually do, what challenges they face, what they post about.
|
|
@@ -8,7 +8,7 @@ Every outreach message must pass one test: "Would the person sending this actual
|
|
|
8
8
|
|
|
9
9
|
## Tone and Voice
|
|
10
10
|
|
|
11
|
-
The sender's identity and tone vary by company. Some senders are founders, some are AEs, some are BDRs. The
|
|
11
|
+
The sender's identity and tone vary by company. Some senders are founders, some are AEs, some are BDRs. The campaign's tone instructions define the specific voice. Always follow them.
|
|
12
12
|
|
|
13
13
|
**Universal rules that apply to every sender:**
|
|
14
14
|
|
|
@@ -53,16 +53,16 @@ This matters more as touch count increases. A 5-touch sequence has fewer angles
|
|
|
53
53
|
|
|
54
54
|
## Touch Sequence Compliance
|
|
55
55
|
|
|
56
|
-
Each
|
|
56
|
+
Each campaign defines its own touch sequence with per-touch instructions, channel, timing, and format constraints. These are the source of truth for what each touch should do.
|
|
57
57
|
|
|
58
58
|
When reviewing a message:
|
|
59
|
-
- Check the touch_number against the
|
|
59
|
+
- Check the touch_number against the campaign's touch_sequence
|
|
60
60
|
- Read the per-touch instructions (these are one-sentence intents the writer interprets)
|
|
61
61
|
- Verify the message follows the intent (e.g., "No pitch, no product mention" means exactly that)
|
|
62
62
|
- Check word/character limits specified for that touch
|
|
63
63
|
- Verify the CTA approach matches the touch stage (early touches typically use questions, later touches may include calendar links, breakup touches have no ask)
|
|
64
64
|
|
|
65
|
-
Do NOT apply hardcoded assumptions about what any touch number should do. A T4 might be a breakup in a 5-touch sequence but a mid-funnel touch in a 15-touch sequence. Always read the
|
|
65
|
+
Do NOT apply hardcoded assumptions about what any touch number should do. A T4 might be a breakup in a 5-touch sequence but a mid-funnel touch in a 15-touch sequence. Always read the campaign's specific instructions.
|
|
66
66
|
|
|
67
67
|
## Personalization Standards
|
|
68
68
|
|
|
@@ -83,22 +83,22 @@ If personalization is surface-level and better data exists in the review context
|
|
|
83
83
|
|
|
84
84
|
## Vertical and Industry Language
|
|
85
85
|
|
|
86
|
-
Each
|
|
86
|
+
Each campaign's selling strategy includes vertical context with industry-native terminology. Messages should use the language the prospect uses, not generic sales language.
|
|
87
87
|
|
|
88
88
|
When reviewing:
|
|
89
|
-
- Check if the message uses terms from the
|
|
90
|
-
- Flag messages that use generic business language when the
|
|
89
|
+
- Check if the message uses terms from the campaign's vertical context
|
|
90
|
+
- Flag messages that use generic business language when the campaign specifies industry terminology
|
|
91
91
|
- The selling strategy's role adaptation section tells you how to frame things differently for different titles (CEO vs VP vs Director, etc.)
|
|
92
92
|
|
|
93
|
-
Do NOT hardcode vertical knowledge. Always pull it from the
|
|
93
|
+
Do NOT hardcode vertical knowledge. Always pull it from the campaign instructions for that specific message.
|
|
94
94
|
|
|
95
95
|
## Channel-Specific Rules
|
|
96
96
|
|
|
97
97
|
**LinkedIn connection requests**: Hard 280 character limit. No exceptions. Count characters, not words.
|
|
98
98
|
|
|
99
|
-
**LinkedIn DMs**: Keep within the word limit specified per touch in the
|
|
99
|
+
**LinkedIn DMs**: Keep within the word limit specified per touch in the campaign's touch sequence. No bullet points or numbered lists. Write like a chat message, not an email.
|
|
100
100
|
|
|
101
|
-
**Email**: Subject line matters. Can be longer and more structured than LinkedIn. Follow the
|
|
101
|
+
**Email**: Subject line matters. Can be longer and more structured than LinkedIn. Follow the campaign's email formatting rules if specified.
|
|
102
102
|
|
|
103
103
|
## Real Examples of Common Failures
|
|
104
104
|
|
|
@@ -113,7 +113,7 @@ Do NOT hardcode vertical knowledge. Always pull it from the segment instructions
|
|
|
113
113
|
|
|
114
114
|
**Bad:** "Worth 15 min to see how it works?" / "Worth a quick call?" / "Open to a brief chat?"
|
|
115
115
|
**Why it fails:** Every automated outreach tool uses this pattern. It's the single biggest AI tell in 2026.
|
|
116
|
-
**Fix:** Follow the
|
|
116
|
+
**Fix:** Follow the campaign's CTA rules for that touch number. Early touches end with questions. Later touches with calendar links should frame them conversationally, not as a close.
|
|
117
117
|
|
|
118
118
|
### Failure: Surface personalization
|
|
119
119
|
|
|
@@ -12,8 +12,8 @@ Call `get_outreach_review` with your assigned `message_ids`, `content_length="fu
|
|
|
12
12
|
|
|
13
13
|
- The draft message content
|
|
14
14
|
- Person info (name, title, company, match score)
|
|
15
|
-
-
|
|
16
|
-
-
|
|
15
|
+
- Campaign tone instructions (including anti-AI-tell rules)
|
|
16
|
+
- Campaign selling strategy and touch sequence
|
|
17
17
|
- Match analysis with alignment points and recommended approach
|
|
18
18
|
- Company research summary
|
|
19
19
|
- Recent LinkedIn posts from the prospect
|
|
@@ -45,7 +45,7 @@ If ANY repetition is found, the message needs a rewrite. This is the most common
|
|
|
45
45
|
|
|
46
46
|
### 2c. AI tell detection
|
|
47
47
|
|
|
48
|
-
Scan the message against the anti-AI-tell rules in the
|
|
48
|
+
Scan the message against the anti-AI-tell rules in the campaign tone instructions. Also check for:
|
|
49
49
|
- Uniform sentence length (every sentence roughly the same word count)
|
|
50
50
|
- Generic opener patterns ("I noticed that...", "I came across your...")
|
|
51
51
|
- Fake personalization (mentioning something vague rather than specific)
|
|
@@ -97,7 +97,7 @@ If the message needs changes, rewrite it and apply the edit using `manage_messag
|
|
|
97
97
|
|
|
98
98
|
When rewriting:
|
|
99
99
|
- Keep the same strategic intent (don't change a T2 into a T4)
|
|
100
|
-
- Follow the
|
|
100
|
+
- Follow the campaign tone instructions exactly
|
|
101
101
|
- Stay within word/character limits
|
|
102
102
|
- Make it sound like something a real person would actually type in a LinkedIn DM
|
|
103
103
|
- Use the selling strategy's role adaptation for this person's title
|
|
@@ -147,7 +147,7 @@ RESEARCH_DONE: {list of extra research you did, or "none"}
|
|
|
147
147
|
- You flagged the message for human review
|
|
148
148
|
- The conversation thread suggests strategic complexity (pricing discussions, objections, competitor mentions)
|
|
149
149
|
- You couldn't find enough context to personalize well
|
|
150
|
-
- The
|
|
150
|
+
- The campaign instructions conflict with what seems like the right approach
|
|
151
151
|
|
|
152
152
|
## Decision Framework
|
|
153
153
|
|
|
@@ -4,7 +4,7 @@ This is the canonical research-engine doc referenced by `/pipeline-fill` (orches
|
|
|
4
4
|
|
|
5
5
|
When a source skill produces a candidate list, it hands off to this engine via the canonical handoff prompt at the bottom of this doc. The engine then runs Steps 3–8: pre-flight → Phase A → Phase B → harness gate → save → report.
|
|
6
6
|
|
|
7
|
-
The orchestrator's SKILL.md owns the front-of-flow:
|
|
7
|
+
The orchestrator's SKILL.md owns the front-of-flow: campaign picker (Step 1), source picker (Step 2), and the inline manual-list parser. Everything from Step 3 onward is defined here. **Don't duplicate this doc in source skills** — link to it.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -37,7 +37,7 @@ All harness source skills produce candidate lists matching this shape exactly. T
|
|
|
37
37
|
|
|
38
38
|
## MCP-availability precheck (load-bearing — runs before Step 3)
|
|
39
39
|
|
|
40
|
-
Before any other Step 3 work, call `fetch(type="research_playbook", id=<
|
|
40
|
+
Before any other Step 3 work, call `fetch(type="research_playbook", id=<campaign_id>)`. If this fails with "tool not found" / 404 / connection error, abort the run with this exact message:
|
|
41
41
|
|
|
42
42
|
> Vruum MCP not configured as a user-scoped server. Run:
|
|
43
43
|
>
|
|
@@ -53,7 +53,7 @@ The research_playbook fetch also doubles as the ICP load — capture target_titl
|
|
|
53
53
|
|
|
54
54
|
## Step 3 — Pre-flight
|
|
55
55
|
|
|
56
|
-
Per
|
|
56
|
+
Per campaign's candidate list:
|
|
57
57
|
|
|
58
58
|
1. **MCP precheck + ICP load** (above) — abort run on failure.
|
|
59
59
|
2. **Batch dedup against existing pipeline.** Call `search(type="people", query=[{name, company, linkedin_url} for each candidate])`. Returns one match record per candidate (in input order). Drop candidates with non-null `match` — they're already in pipeline.
|
|
@@ -75,11 +75,11 @@ Dispatch one `vruum-company-deep-researcher` per unique uncached company. Subage
|
|
|
75
75
|
Dispatch prompt template (fill in placeholders):
|
|
76
76
|
|
|
77
77
|
```
|
|
78
|
-
You are vruum-company-deep-researcher. Research this company against
|
|
78
|
+
You are vruum-company-deep-researcher. Research this company against campaign "{campaign_name}".
|
|
79
79
|
|
|
80
80
|
company_name: {name}
|
|
81
81
|
domain: {domain}
|
|
82
|
-
|
|
82
|
+
campaign_icp_summary: {one paragraph from the research_playbook fetch}
|
|
83
83
|
acv_floor: {dollars or default $10K}
|
|
84
84
|
|
|
85
85
|
Run your workflow (a–i) and return the structured output block.
|
|
@@ -108,7 +108,7 @@ Dispatch one `vruum-prospect-deep-researcher` per surviving candidate. Subagent
|
|
|
108
108
|
Dispatch prompt template:
|
|
109
109
|
|
|
110
110
|
```
|
|
111
|
-
You are vruum-prospect-deep-researcher. Research this prospect against
|
|
111
|
+
You are vruum-prospect-deep-researcher. Research this prospect against campaign "{campaign_name}".
|
|
112
112
|
|
|
113
113
|
full_name: {name}
|
|
114
114
|
first_name: {first_name or null}
|
|
@@ -122,7 +122,7 @@ phase_a_signals:
|
|
|
122
122
|
outbound_motion_score: {0|1|2 or null}
|
|
123
123
|
triggers: [list or null]
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
campaign_icp_summary: {one paragraph from the research_playbook fetch}
|
|
126
126
|
acv_floor: {dollars}
|
|
127
127
|
|
|
128
128
|
Run your workflow (a–k) and return the structured output block. Note: do NOT call manage_person action=save_discovered or manage_outreach action=start — those are orchestrator-only and not in your tools list.
|
|
@@ -141,19 +141,19 @@ Each subagent returns: `topics_of_interest`, `recent_posts`, `opening_hooks[]` (
|
|
|
141
141
|
|
|
142
142
|
This is a **coarse pre-filter** — its job is to avoid wasted backend save calls (`manage_person` action=save_discovered) on obvious dismisses. The **authoritative** gate is server-side `MatchAnalysisAgent.match_score >= 70` and runs inside that save call. The harness gate cannot override the backend gate; it can only dismiss before reaching it.
|
|
143
143
|
|
|
144
|
-
Per surviving prospect, evaluate four criteria using the
|
|
144
|
+
Per surviving prospect, evaluate four criteria using the campaign's playbook ICP and the Phase A + Phase B signals:
|
|
145
145
|
|
|
146
|
-
### 1. ACV class meets
|
|
147
|
-
- `acv_class >= acv_floor_class` → pass this criterion (smb=$5K, mid=$5–50K, ent=$50K+;
|
|
146
|
+
### 1. ACV class meets campaign threshold?
|
|
147
|
+
- `acv_class >= acv_floor_class` → pass this criterion (smb=$5K, mid=$5–50K, ent=$50K+; campaign's `acv_floor` from playbook maps to a class)
|
|
148
148
|
- If no → dismiss `acv_too_low`. Don't call `manage_person` action=save_discovered.
|
|
149
149
|
|
|
150
150
|
### 2. Outbound motion or hiring signal?
|
|
151
151
|
- `outbound_motion_score > 0` OR explicit hiring trigger present → pass
|
|
152
|
-
- If no → flag `warming_candidate` (still call `manage_person` action=save_discovered — operator may want to warm-track them; backend match analysis tells us if the
|
|
152
|
+
- If no → flag `warming_candidate` (still call `manage_person` action=save_discovered — operator may want to warm-track them; backend match analysis tells us if the campaign fit is real)
|
|
153
153
|
|
|
154
154
|
### 3. Decision-maker level senior?
|
|
155
155
|
- `decision_maker_level == senior` → pass
|
|
156
|
-
- If `mid` → pass with a note (
|
|
156
|
+
- If `mid` → pass with a note (campaign owner decides if mid is acceptable)
|
|
157
157
|
- If `junior` → look for a more-senior person at the same `company_id` in the Phase B output set. If found, swap and rerun. If not, dismiss `decision_maker_junior`.
|
|
158
158
|
|
|
159
159
|
### 4. Trigger event in last 90d?
|
|
@@ -217,18 +217,18 @@ If the prospect's company isn't already cached and Phase A produced fresh resear
|
|
|
217
217
|
|
|
218
218
|
### c. Save discovered person (the backend authoritative gate runs here)
|
|
219
219
|
|
|
220
|
-
Call `manage_person(action="save_discovered", payload={person_id: <from b>,
|
|
220
|
+
Call `manage_person(action="save_discovered", payload={person_id: <from b>, campaign_id: ...})`. This:
|
|
221
221
|
- Runs server-side `analyze_person_match` + signal eval
|
|
222
222
|
- Returns `match_score` (0–100) and `quality_gate_pass` (bool, true iff `match_score >= 70`)
|
|
223
|
-
- Writes the `company_people` row that puts the prospect into the
|
|
223
|
+
- Writes the `company_people` row that puts the prospect into the campaign
|
|
224
224
|
|
|
225
225
|
**Distinguish two failure modes (Codex Finding #9):**
|
|
226
226
|
- **Request failure (5xx, timeout, network):** retry once with 2s backoff. If still failing, leave the prospect in `discovery_failed` status and surface in the final report. **Don't** claim "saved as gate-fail" — the row was never written.
|
|
227
|
-
- **Request success + low score (`quality_gate_pass: false`):** the prospect IS saved with research; backend marks gate-fail; surface for operator review. This is a soft-fail. The prospect is on file with full research, useful for future
|
|
227
|
+
- **Request success + low score (`quality_gate_pass: false`):** the prospect IS saved with research; backend marks gate-fail; surface for operator review. This is a soft-fail. The prospect is on file with full research, useful for future campaigns.
|
|
228
228
|
|
|
229
229
|
### d. Bulk enrollment (only after all prospects saved)
|
|
230
230
|
|
|
231
|
-
Collect all `person_id`s where `harness_gate_status == pass` AND backend `quality_gate_pass == true` AND `mode == save-and-enroll`. Then call `manage_outreach(action="start", id=[those person_ids], payload={
|
|
231
|
+
Collect all `person_id`s where `harness_gate_status == pass` AND backend `quality_gate_pass == true` AND `mode == save-and-enroll`. Then call `manage_outreach(action="start", id=[those person_ids], payload={campaign_id: ...})` ONCE at the end of Step 7.
|
|
232
232
|
|
|
233
233
|
- Per-prospect outcomes are returned (enrolled | skipped | failed). Surface per-prospect failures in the report.
|
|
234
234
|
- If `harness_gate_status` is `warming` or `low_priority`, exclude from the bulk enroll list. Operator decides on review.
|
|
@@ -241,7 +241,7 @@ Collect all `person_id`s where `harness_gate_status == pass` AND backend `qualit
|
|
|
241
241
|
Print to chat AND write to `.context/runs/pipeline-fill-{ISO-timestamp}.md` (workspace-local; `.context/` is gitignored per CLAUDE.md). Format identical for both surfaces.
|
|
242
242
|
|
|
243
243
|
```
|
|
244
|
-
Pipeline fill complete: {
|
|
244
|
+
Pipeline fill complete: {campaign_name} (source: {source}, mode: {harness|platform})
|
|
245
245
|
|
|
246
246
|
Candidates flow:
|
|
247
247
|
source : {N from source skill output}
|
|
@@ -274,14 +274,14 @@ Pool status: healthy | drying up | exhausted ⚠️
|
|
|
274
274
|
Audit log written: .context/runs/pipeline-fill-{timestamp}.md
|
|
275
275
|
```
|
|
276
276
|
|
|
277
|
-
For multi-
|
|
277
|
+
For multi-campaign runs, group the report by campaign and include a totals summary at the bottom.
|
|
278
278
|
|
|
279
279
|
---
|
|
280
280
|
|
|
281
281
|
## Edge cases + failure handling reference
|
|
282
282
|
|
|
283
283
|
- **Source returns empty after dedup** — orchestrator says "All {N} candidates already in pipeline, nothing to research" and exits cleanly.
|
|
284
|
-
- **Mid-flight cancellation** (operator Ctrl+C between Phase A and Phase B) — Phase A research is saved server-side. Re-running `/pipeline-fill` for the same
|
|
284
|
+
- **Mid-flight cancellation** (operator Ctrl+C between Phase A and Phase B) — Phase A research is saved server-side. Re-running `/pipeline-fill` for the same campaign + source picks up via batch dedup; no re-research of cached companies. Note this in the cancellation message.
|
|
285
285
|
- **Subagent timeout cascade** — Phase A failed for a company → Phase B runs degraded → harness gate marks `gate_inconclusive` → backend decides via cached company research. See Step 4.
|
|
286
286
|
- **Two-gate disagreement** — harness pass + backend fail (or vice versa) → see Step 7c. Stricter outcome wins for enrollment; both states surfaced in the report.
|
|
287
287
|
- **Cached company research >90 days old** — Phase A re-runs the company subagent. Don't trust stale signals for an active fill.
|
|
@@ -299,7 +299,7 @@ When a HARNESS source skill completes its sourcing flow and has a candidate list
|
|
|
299
299
|
```
|
|
300
300
|
Candidate list ready: {N} prospects from {source}.
|
|
301
301
|
|
|
302
|
-
NEXT: invoke /pipeline-fill Step 3 onward (deep research → harness gate → save) with this list and
|
|
302
|
+
NEXT: invoke /pipeline-fill Step 3 onward (deep research → harness gate → save) with this list and campaign {campaign_id}.
|
|
303
303
|
|
|
304
304
|
Continue automatically? (y/n)
|
|
305
305
|
```
|
|
@@ -9,19 +9,19 @@ description: >-
|
|
|
9
9
|
---
|
|
10
10
|
# Pipeline Fill
|
|
11
11
|
|
|
12
|
-
You are a source-agnostic pipeline filler. You pick
|
|
12
|
+
You are a source-agnostic pipeline filler. You pick campaigns to fill, pick a source per campaign (Sales Nav / YC / CSV / discovery), and orchestrate harness deep research that gates against the campaign ICP before saving prospects into the backend pipeline.
|
|
13
13
|
|
|
14
14
|
## Why this skill exists
|
|
15
15
|
|
|
16
|
-
Filling your pipeline by source-of-the-day is normal. Sales Nav drying up doesn't mean you're stuck — pick YC, paste a CSV, or run discovery (paste candidates OR describe an ICP and the harness sources them via WebSearch + Vruum MCP + LinkedIn search). This skill orchestrates deep research per prospect in your IDE (your compute), pre-filters against
|
|
16
|
+
Filling your pipeline by source-of-the-day is normal. Sales Nav drying up doesn't mean you're stuck — pick YC, paste a CSV, or run discovery (paste candidates OR describe an ICP and the harness sources them via WebSearch + Vruum MCP + LinkedIn search). This skill orchestrates deep research per prospect in your IDE (your compute), pre-filters against campaign ICP, then saves the qualified ones into the campaign via the backend's canonical gate.
|
|
17
17
|
|
|
18
18
|
## Where the heavy logic lives
|
|
19
19
|
|
|
20
20
|
Steps 3–8 (pre-flight, Phase A research, Phase B research, harness gate, save chain, audit-log report) are defined in `RESEARCH-ENGINE.md` (in this same skill directory). This skill owns:
|
|
21
|
-
- Step 1:
|
|
21
|
+
- Step 1: campaign picker (with ETA)
|
|
22
22
|
- Step 2: source picker (conditional PLATFORM block + always-visible HARNESS block)
|
|
23
23
|
- The discovery-mode handler (paste candidates inline OR describe an ICP and source via harness tools)
|
|
24
|
-
- The multi-
|
|
24
|
+
- The multi-campaign grammar
|
|
25
25
|
|
|
26
26
|
When you reach Step 3, **stop and read** `RESEARCH-ENGINE.md`. That doc is the canonical source for the candidate-list shape, the harness gate criteria, the identity-resolution save chain, and the canonical handoff prompt that source skills use.
|
|
27
27
|
|
|
@@ -50,13 +50,13 @@ The orchestrator's MCP precheck at the top of Step 3 (the `fetch` type=research_
|
|
|
50
50
|
## Inputs
|
|
51
51
|
|
|
52
52
|
- `prospect_list` (optional): pre-built candidate list matching the canonical shape in `RESEARCH-ENGINE.md`. If provided, skip the source-picker step and go straight to Step 3 (pre-flight). This is how source skills hand off.
|
|
53
|
-
- `
|
|
53
|
+
- `campaign(s)`: target campaign(s); multi-campaign supported.
|
|
54
54
|
- `mode`: `research-only` | `save` | `save-and-enroll` (default: `save-and-enroll`).
|
|
55
|
-
- `gate_threshold`: minimum backend `match_score` to enroll (default:
|
|
55
|
+
- `gate_threshold`: minimum backend `match_score` to enroll (default: campaign's existing quality_gate).
|
|
56
56
|
|
|
57
|
-
## Workflow — Step 1: Show pipeline status & pick
|
|
57
|
+
## Workflow — Step 1: Show pipeline status & pick campaigns
|
|
58
58
|
|
|
59
|
-
Call `import_prospects(action="sales_nav_searches", payload={action: "list"})` + `fetch(type="stats", subtype="outreach")` for queue depth + `search(type="campaigns")` for non-Sales-Nav
|
|
59
|
+
Call `import_prospects(action="sales_nav_searches", payload={action: "list"})` + `fetch(type="stats", subtype="outreach")` for queue depth + `search(type="campaigns")` for non-Sales-Nav campaigns. Present a numbered table with **per-campaign ETA**:
|
|
60
60
|
|
|
61
61
|
```
|
|
62
62
|
Pipeline status:
|
|
@@ -66,29 +66,29 @@ Pipeline status:
|
|
|
66
66
|
3. Houston CTOs — 0/20 (20 needed) — harness ETA: ~18m
|
|
67
67
|
4. NYC Partners — 40/40 ✓
|
|
68
68
|
|
|
69
|
-
Which
|
|
69
|
+
Which campaigns to fill? (all / 1,3 / skip 2)
|
|
70
70
|
Total if all needing fill: ~37m sequential.
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
ETA estimates: ~2s for batch Step 3 dedup + ~30s/wave Phase A + ~60s/wave Phase B (5-parallel cap on Phase B). Multi-
|
|
73
|
+
ETA estimates: ~2s for batch Step 3 dedup + ~30s/wave Phase A + ~60s/wave Phase B (5-parallel cap on Phase B). Multi-campaign ETAs are sequential.
|
|
74
74
|
|
|
75
75
|
**Table rules:**
|
|
76
|
-
- One row per
|
|
76
|
+
- One row per campaign, numbered sequentially
|
|
77
77
|
- Show current/target counts and how many are needed
|
|
78
78
|
- Flag searches that are drying up (⚠️) or accounts near capacity
|
|
79
|
-
- Mark
|
|
80
|
-
- Show per-
|
|
79
|
+
- Mark campaigns already at target with ✓ and don't number them
|
|
80
|
+
- Show per-campaign ETA so operator can budget time
|
|
81
81
|
|
|
82
|
-
**Wait for the user's response.** Parse: "all", "1, 3", "skip 2", "just the CFO ones", etc. Only proceed with the selected
|
|
82
|
+
**Wait for the user's response.** Parse: "all", "1, 3", "skip 2", "just the CFO ones", etc. Only proceed with the selected campaigns.
|
|
83
83
|
|
|
84
|
-
## Workflow — Step 2: Pick source per
|
|
84
|
+
## Workflow — Step 2: Pick source per campaign (only if `prospect_list` not provided)
|
|
85
85
|
|
|
86
|
-
Per selected
|
|
86
|
+
Per selected campaign, prompt:
|
|
87
87
|
|
|
88
88
|
In **public mode** (the package builder strips the PLATFORM block from this skill before publishing), the picker shows only HARNESS modes, renumbered 1–4:
|
|
89
89
|
|
|
90
90
|
```
|
|
91
|
-
Source for {
|
|
91
|
+
Source for {campaign_name}?
|
|
92
92
|
HARNESS mode (your compute, in-chat deep research, visible & interruptible):
|
|
93
93
|
1. sales-nav-deep — Sales Nav profiles + harness deep research
|
|
94
94
|
2. yc — scrape YC directory with filters you provide
|
|
@@ -107,7 +107,7 @@ Per source pick, dispatch:
|
|
|
107
107
|
- `csv` → invoke `/csv-pipeline-fill` to produce a candidate list, then continue to Step 3 with it.
|
|
108
108
|
- `discovery` → use the discovery-mode handler below to produce a candidate list (handler branches: paste-shaped input → parse, prose ICP brief → harness sources via WebSearch + Vruum MCP + LinkedIn search), then continue to Step 3 with it.
|
|
109
109
|
|
|
110
|
-
**Multi-
|
|
110
|
+
**Multi-campaign behavior:** campaigns run sequentially. Campaign 1's Step 7 (save chain + bulk enroll) completes before campaign 2's Step 3 starts. Predictable rate-limit behavior, simple progress narrative. Trade-off: 3-campaign fills are ~37min wall-clock vs ~22min if Phase A/B were overlapped across campaigns. Cross-campaign overlap is a v2.
|
|
111
111
|
|
|
112
112
|
## Discovery-mode handler (for `discovery` source)
|
|
113
113
|
|
|
@@ -127,13 +127,13 @@ Drop blank lines and lines starting with `#` (treat as comments).
|
|
|
127
127
|
**Path B — operator describes an ICP** (you want the harness to discover candidates)
|
|
128
128
|
Operator gives a brief like "Series A-C SaaS founders, US, 50-500 ppl" or "directors of operations at MSPs in DFW, recently posted about hiring". Harness sources candidates from scratch:
|
|
129
129
|
|
|
130
|
-
1. **Anchor on
|
|
130
|
+
1. **Anchor on campaign ICP** — read the campaign's existing ICP/company profile (via `fetch` type=campaign and `fetch` type=settings subtype=profile) and merge with the operator's brief. Show a one-line synthesis ("OK so: Series A-C SaaS, US, 50-500 ppl, founder/CEO/CTO titles") and confirm before sourcing.
|
|
131
131
|
2. **Source companies first** — use harness tools to find candidate companies matching the brief:
|
|
132
132
|
- `WebSearch` for funding announcements, news, lists ("Series A SaaS 2026", "TechCrunch Series B SaaS announcements")
|
|
133
133
|
- `WebFetch` on Crunchbase / PitchBook / company directories
|
|
134
134
|
- `mcp__vruum__import_prospects` with action=sales_nav_search (payload={keywords, title, limit}) for company-fitting roles when the brief is people-shaped (e.g. "VPs of Eng at Series A SaaS")
|
|
135
|
-
3. **Source people from each company** — for each candidate company, use `mcp__vruum__search` with type=companies and filters={domain, seniority} (Unipile-backed; respects LinkedIn rate limits) to find titles matching the
|
|
136
|
-
4. **Dedup against existing pipeline** — for each discovered person, check `mcp__vruum__search` with type=people and a name/company keyword query so you don't research someone the
|
|
135
|
+
3. **Source people from each company** — for each candidate company, use `mcp__vruum__search` with type=companies and filters={domain, seniority} (Unipile-backed; respects LinkedIn rate limits) to find titles matching the campaign ICP. Cap at ~5 people per company to spread the discovery surface.
|
|
136
|
+
4. **Dedup against existing pipeline** — for each discovered person, check `mcp__vruum__search` with type=people and a name/company keyword query so you don't research someone the campaign already has.
|
|
137
137
|
5. **Show the discovered list to the operator** before handoff. Format: `Name (title) — Company [linkedin]`. Cap the surface at 2x daily_target so we don't over-source. Get a "go" / "drop X" before continuing.
|
|
138
138
|
|
|
139
139
|
Discovery-path candidates produced in either path use the canonical shape in `RESEARCH-ENGINE.md` and feed into Step 3 the same way.
|
|
@@ -14,18 +14,18 @@ You are the Sales Nav harness-mode source for `/pipeline-fill`. You produce a ca
|
|
|
14
14
|
|
|
15
15
|
## Inputs
|
|
16
16
|
|
|
17
|
-
- `
|
|
17
|
+
- `campaign`: target campaign (single — multi-campaign lives in `/pipeline-fill`)
|
|
18
18
|
- `count`: how many profiles to pre-filter (default 30)
|
|
19
19
|
|
|
20
20
|
## Workflow
|
|
21
21
|
|
|
22
22
|
### Step 1: Preview Sales Nav profiles
|
|
23
23
|
|
|
24
|
-
Call `import_prospects(action="sales_nav_preview", payload={
|
|
24
|
+
Call `import_prospects(action="sales_nav_preview", payload={campaign: ..., count: ...})`. Returns profile data + campaign ICP context (target_titles, target_industries, value_proposition, positioning_angle, differentiators).
|
|
25
25
|
|
|
26
26
|
### Step 2: Dispatch `vruum-pipeline-filter` for ICP pre-filter
|
|
27
27
|
|
|
28
|
-
Spawn the existing `vruum-pipeline-filter` subagent (defined at `.claude/agents/vruum-pipeline-filter.md`). It evaluates each profile against the
|
|
28
|
+
Spawn the existing `vruum-pipeline-filter` subagent (defined at `.claude/agents/vruum-pipeline-filter.md`). It evaluates each profile against the campaign ICP using cheap title/company matching — no LinkedIn API calls, no deep research. APPROVE / DISMISS per profile.
|
|
29
29
|
|
|
30
30
|
This is the cheap pre-filter — it removes obvious mismatches (titled-wrong, industry-wrong) before they enter Phase A/B deep research. Saves ~8 minutes per fill on a 30-profile preview that has 10 mismatches.
|
|
31
31
|
|
|
@@ -47,7 +47,7 @@ Emit the canonical handoff prompt (defined in `pipeline-fill/RESEARCH-ENGINE.md`
|
|
|
47
47
|
```
|
|
48
48
|
Candidate list ready: {N} prospects from sales-nav-deep.
|
|
49
49
|
|
|
50
|
-
NEXT: invoke /pipeline-fill Step 3 onward (deep research → harness gate → save) with this list and
|
|
50
|
+
NEXT: invoke /pipeline-fill Step 3 onward (deep research → harness gate → save) with this list and campaign {campaign_id}.
|
|
51
51
|
|
|
52
52
|
Continue automatically? (y/n)
|
|
53
53
|
```
|
|
@@ -67,10 +67,13 @@ Force a fresh check first, then run the flow above starting from Step 2:
|
|
|
67
67
|
~/.vruum/bin/vruum-skills-update-check --force
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
Interpret the forced check's output:
|
|
71
|
+
- Returns nothing → genuinely up to date. Report `already on latest (v$(cat ~/.vruum/VERSION))` and exit.
|
|
72
|
+
- `CHECK_FAILED <local>` → the registry could NOT be reached (network/sandbox), so we do **not** know if you're current. Report `upgrade check failed — couldn't reach the npm registry (network/sandbox); not necessarily on latest. Try again later or from an unsandboxed shell.` Do NOT claim "already on latest." (A forced check emits this whenever the fetch fails; a sandbox that blocks the registry is the common cause.)
|
|
73
|
+
- `UPGRADE_AVAILABLE <old> <new>` → run the upgrade flow from Step 2.
|
|
71
74
|
|
|
72
75
|
## When something goes wrong
|
|
73
76
|
|
|
74
77
|
- `npm install` fails with permissions → tell the user to re-run with `sudo` or fix their npm prefix. Don't auto-sudo.
|
|
75
78
|
- `vruum-skills install` reports skipped skills → surface the conflict message verbatim; user needs to remove conflicting files.
|
|
76
|
-
- Network failure on registry lookup →
|
|
79
|
+
- Network failure on registry lookup → the forced check now emits `CHECK_FAILED <local>` (it no longer silently looks up to date). Report `upgrade check failed, try again later` and continue with the original skill (don't block work on a transient fetch error).
|
|
@@ -84,7 +84,7 @@ If no hook can be generated → defer the row. Warm via marketing/content first,
|
|
|
84
84
|
|
|
85
85
|
Step 6 — Hand off. Two options:
|
|
86
86
|
- **Option A (recommended)**: Approve the list; run `/pipeline-fill` with the prospect_list for harness deep research + outreach. Plans get `outreach_plans.tag = bowtie_pilot:winback`.
|
|
87
|
-
- **Option B**: Direct `manage_outreach` action=start with a winback-flavored
|
|
87
|
+
- **Option B**: Direct `manage_outreach` action=start with a winback-flavored campaign (pre-create a `winback_<your-tenant>` campaign — tone: empathetic, no apology, lead with what changed since last conversation).
|
|
88
88
|
|
|
89
89
|
Step 7 — Success tracking (auto). The calendar webhook records the impact event, equivalent to:
|
|
90
90
|
```
|
|
@@ -10,11 +10,11 @@ description: >-
|
|
|
10
10
|
|
|
11
11
|
You are the YCombinator harness-mode source for `/pipeline-fill`. You scrape YC's public directory, extract founder LinkedIn URLs, dedup, and hand a candidate list to the orchestrator. No deep research, no harness gate, no save chain in this skill — that's all in `pipeline-fill/RESEARCH-ENGINE.md`.
|
|
12
12
|
|
|
13
|
-
This is the answer to "DFW CFOs Sales Nav is dead, what now?" — pivot to YC, get 30 founders into the
|
|
13
|
+
This is the answer to "DFW CFOs Sales Nav is dead, what now?" — pivot to YC, get 30 founders into the campaign in ~15 minutes.
|
|
14
14
|
|
|
15
15
|
## Inputs
|
|
16
16
|
|
|
17
|
-
- `
|
|
17
|
+
- `campaign`: target campaign (single)
|
|
18
18
|
- `count`: target number of imports (default 50)
|
|
19
19
|
- `filters` (REQUIRED — no defaults; operator must specify at least one):
|
|
20
20
|
- `team_size_min` / `team_size_max` (proxy for funding stage)
|
|
@@ -27,9 +27,9 @@ If the operator runs the skill without filters, prompt: "YC has 5K+ companies
|
|
|
27
27
|
|
|
28
28
|
## Workflow
|
|
29
29
|
|
|
30
|
-
### Step 1: Load
|
|
30
|
+
### Step 1: Load campaign ICP
|
|
31
31
|
|
|
32
|
-
Call `fetch` type=research_playbook id=<
|
|
32
|
+
Call `fetch` type=research_playbook id=<campaign_id> to load ICP context. The downstream subagents need it for classification; capture it now to pass forward.
|
|
33
33
|
|
|
34
34
|
### Step 2: Algolia connectivity precheck
|
|
35
35
|
|
|
@@ -149,7 +149,7 @@ Emit the canonical handoff prompt (defined in `pipeline-fill/RESEARCH-ENGINE.md`
|
|
|
149
149
|
```
|
|
150
150
|
Candidate list ready: {N} prospects from yc.
|
|
151
151
|
|
|
152
|
-
NEXT: invoke /pipeline-fill Step 3 onward (deep research → harness gate → save) with this list and
|
|
152
|
+
NEXT: invoke /pipeline-fill Step 3 onward (deep research → harness gate → save) with this list and campaign {campaign_id}.
|
|
153
153
|
|
|
154
154
|
Continue automatically? (y/n)
|
|
155
155
|
```
|