@anysiteio/agent-skills 1.4.0 → 2.0.1
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/marketplace.json +49 -1
- package/.claude-plugin/plugin.json +5 -1
- package/README.md +27 -33
- package/bin/install.js +196 -135
- package/bundles.json +19 -0
- package/package.json +3 -2
- package/skills/anysite-audience-analysis/SKILL.md +110 -38
- package/skills/anysite-audience-analysis/references/PLATFORM_COVERAGE.md +38 -19
- package/skills/anysite-audience-analysis/references/TOOL_MAPPING.md +16 -11
- package/skills/anysite-brand-reputation/SKILL.md +105 -43
- package/skills/anysite-competitor-analyzer/SKILL.md +170 -111
- package/skills/anysite-competitor-intelligence/SKILL.md +201 -116
- package/skills/anysite-competitor-intelligence/references/ANALYSIS_PATTERNS.md +17 -13
- package/skills/anysite-content-analytics/SKILL.md +101 -33
- package/skills/anysite-crm-account-brief/SKILL.md +71 -0
- package/skills/anysite-crm-audit/SKILL.md +59 -0
- package/skills/anysite-crm-champions/SKILL.md +76 -0
- package/skills/anysite-crm-competitor-intel/SKILL.md +74 -0
- package/skills/anysite-crm-enrich/SKILL.md +84 -0
- package/skills/anysite-crm-lookalikes/SKILL.md +64 -0
- package/skills/anysite-crm-prospect/SKILL.md +90 -0
- package/skills/anysite-crm-score/SKILL.md +72 -0
- package/skills/anysite-crm-setup/SKILL.md +147 -0
- package/skills/anysite-crm-signals/SKILL.md +96 -0
- package/skills/anysite-influencer-discovery/SKILL.md +123 -71
- package/skills/anysite-lead-generation/SKILL.md +288 -256
- package/skills/anysite-lead-generation/references/LINKEDIN_STRATEGIES.md +79 -71
- package/skills/anysite-lead-generation/references/WEB_SCRAPING.md +121 -87
- package/skills/anysite-market-research/SKILL.md +117 -68
- package/skills/anysite-mcp/SKILL.md +128 -0
- package/skills/anysite-mcp-migration/SKILL.md +19 -8
- package/skills/anysite-person-analyzer/SKILL.md +86 -53
- package/skills/anysite-trend-analysis/SKILL.md +119 -55
- package/skills/anysite-vc-analyst/SKILL.md +12 -2
- package/skills/competitor-discovery/SKILL.md +350 -0
- package/skills/customer-pain-mining/SKILL.md +318 -0
- package/skills/positioning-map/SKILL.md +314 -0
|
@@ -9,23 +9,25 @@ Frameworks and templates for analyzing competitors using anysite MCP data.
|
|
|
9
9
|
**Strengths**:
|
|
10
10
|
```
|
|
11
11
|
LinkedIn:
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
12
|
+
- execute("linkedin", "company", "company", {"company": "..."}) → Company size, growth
|
|
13
|
+
- execute("linkedin", "company", "company_posts", {"urn": ..., "count": 20}) → Messaging, brand strength
|
|
14
|
+
- execute("linkedin", "search", "search_users", {"company_keywords": "...", "title": "...", "count": 50}) → Leadership quality
|
|
15
15
|
|
|
16
16
|
Y Combinator:
|
|
17
|
-
-
|
|
17
|
+
- execute("yc", "company", "get", {"slug": "..."}) → Funding, pedigree
|
|
18
18
|
|
|
19
19
|
Social:
|
|
20
20
|
- Follower counts, engagement rates
|
|
21
21
|
- Content quality and frequency
|
|
22
|
+
- Use query_cache(cache_key, aggregate=[{"field": "like_count", "function": "avg"}]) for engagement benchmarks
|
|
22
23
|
```
|
|
23
24
|
|
|
24
25
|
**Weaknesses**:
|
|
25
26
|
```
|
|
26
27
|
Reddit:
|
|
27
|
-
-
|
|
28
|
+
- execute("reddit", "search", "search_posts", {"query": "competitor", "count": 50}) → Customer complaints
|
|
28
29
|
- Product gaps, feature requests
|
|
30
|
+
- Use query_cache(cache_key, sort_by=[{"field": "comment_count", "order": "desc"}]) to find most-discussed issues
|
|
29
31
|
|
|
30
32
|
LinkedIn:
|
|
31
33
|
- Employee turnover (departures)
|
|
@@ -48,8 +50,8 @@ Market gaps identified through:
|
|
|
48
50
|
**Threats**:
|
|
49
51
|
```
|
|
50
52
|
Competitive threats:
|
|
51
|
-
- YC batch analysis (new entrants)
|
|
52
|
-
- Hiring velocity (aggressive growth)
|
|
53
|
+
- YC batch analysis (new entrants): execute("yc", "search", "search_companies", {"query": "...", "count": 50})
|
|
54
|
+
- Hiring velocity (aggressive growth): execute("linkedin", "company", "company_employee_stats", {"urn": ...})
|
|
53
55
|
- New product launches
|
|
54
56
|
- Pricing changes
|
|
55
57
|
```
|
|
@@ -63,16 +65,18 @@ Competitive threats:
|
|
|
63
65
|
4. Customer Type (Technical vs. Business Users)
|
|
64
66
|
|
|
65
67
|
**Data Sources**:
|
|
66
|
-
- Website messaging
|
|
67
|
-
- LinkedIn company description
|
|
68
|
-
- Pricing pages
|
|
69
|
-
- Job postings (
|
|
68
|
+
- Website messaging: `execute("webparser", "parse", "parse", {"url": "..."})`
|
|
69
|
+
- LinkedIn company description: `execute("linkedin", "company", "company", {"company": "..."})`
|
|
70
|
+
- Pricing pages: `execute("webparser", "parse", "parse", {"url": "<website>/pricing"})`
|
|
71
|
+
- Job postings: `execute("linkedin", "search", "search_jobs", {"keywords": "...", "count": 50})`
|
|
72
|
+
|
|
73
|
+
**Export**: Use `export_data(cache_key, "csv")` to build comparison spreadsheets.
|
|
70
74
|
|
|
71
75
|
## Porter's Five Forces Analysis
|
|
72
76
|
|
|
73
77
|
**Threat of New Entrants**:
|
|
74
|
-
- Monitor YC batches for new competitors
|
|
75
|
-
- Track LinkedIn company formations in space
|
|
78
|
+
- Monitor YC batches for new competitors: `execute("yc", "search", "search_companies", {"query": "...", "count": 50})`
|
|
79
|
+
- Track LinkedIn company formations in space: `execute("linkedin", "search", "search_companies", {"keywords": "...", "count": 50})`
|
|
76
80
|
- Watch for well-funded startups
|
|
77
81
|
|
|
78
82
|
**Competitive Rivalry**:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: anysite-content-analytics
|
|
3
|
-
description: Track and analyze content performance across Instagram, YouTube, LinkedIn, Twitter/X, and Reddit using anysite MCP server. Measure engagement metrics, analyze post effectiveness, benchmark content strategy, identify top-performing content, and optimize posting strategies.
|
|
3
|
+
description: Track and analyze content performance across Instagram, YouTube, LinkedIn, Twitter/X, and Reddit using anysite MCP server. Measure engagement metrics, analyze post effectiveness, benchmark content strategy, identify top-performing content, and optimize posting strategies. Use when users need to measure content ROI, optimize social strategy, identify viral content patterns, or analyze content engagement across platforms.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# anysite Content Analytics
|
|
@@ -25,18 +25,39 @@ Measure and optimize content performance across social platforms using anysite M
|
|
|
25
25
|
- ✅ **Twitter/X**: Tweets, retweets, likes, replies
|
|
26
26
|
- ✅ **Reddit**: Posts, upvotes, comments, awards
|
|
27
27
|
|
|
28
|
+
## v2 Tool Interface
|
|
29
|
+
|
|
30
|
+
All data fetching uses the anysite MCP v2 universal meta-tools:
|
|
31
|
+
|
|
32
|
+
- **`execute(source, category, endpoint, params)`** - Fetch data from any source. Returns first page + `cache_key`.
|
|
33
|
+
- **`get_page(cache_key, offset, limit)`** - Load more items from a previous execute() when `next_offset` is returned.
|
|
34
|
+
- **`query_cache(cache_key, conditions?, sort_by?, aggregate?, group_by?)`** - Filter, sort, and aggregate cached data without new API calls.
|
|
35
|
+
- **`export_data(cache_key, format)`** - Export full dataset as CSV, JSON, or JSONL. Returns a download URL.
|
|
36
|
+
|
|
37
|
+
### Error Handling
|
|
38
|
+
|
|
39
|
+
v2 responses may include `llm_hint` fields with guidance on how to resolve errors. Common patterns:
|
|
40
|
+
- **412**: Entity not found - verify the identifier (username, URN, URL).
|
|
41
|
+
- **422**: Invalid parameter format - check URN prefix format or param types.
|
|
42
|
+
- Always check `llm_hint` in error responses for specific resolution steps.
|
|
43
|
+
|
|
28
44
|
## Quick Start
|
|
29
45
|
|
|
30
46
|
**Step 1: Collect Content Data**
|
|
31
47
|
|
|
32
48
|
Platform-specific:
|
|
33
|
-
- Instagram: `
|
|
34
|
-
- LinkedIn: `
|
|
35
|
-
- Twitter: `
|
|
36
|
-
- YouTube: `
|
|
49
|
+
- Instagram: `execute("instagram", "user", "user_posts", {"user": "username", "count": 50})`
|
|
50
|
+
- LinkedIn: `execute("linkedin", "user", "user_posts", {"urn": "fsd_profile:ACoAAA...", "count": 50})`
|
|
51
|
+
- Twitter: `execute("twitter", "user", "user_posts", {"user": "username", "count": 100})`
|
|
52
|
+
- YouTube: `execute("youtube", "channel", "channel_videos", {"channel": "channel_id", "count": 30})`
|
|
37
53
|
|
|
38
54
|
**Step 2: Analyze Engagement**
|
|
39
55
|
|
|
56
|
+
Use `query_cache()` on the returned `cache_key` to analyze without re-fetching:
|
|
57
|
+
```
|
|
58
|
+
query_cache(cache_key, sort_by="likes desc", aggregate="avg:likes,comments")
|
|
59
|
+
```
|
|
60
|
+
|
|
40
61
|
Calculate metrics:
|
|
41
62
|
- Engagement rate: (likes + comments + shares) / followers
|
|
42
63
|
- Best performing content: Top 10% by engagement
|
|
@@ -59,6 +80,14 @@ Based on findings:
|
|
|
59
80
|
- Replicate successful topics
|
|
60
81
|
- Adjust content mix
|
|
61
82
|
|
|
83
|
+
**Step 5: Export Results**
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
export_data(cache_key, "csv")
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Returns a download URL for the full dataset.
|
|
90
|
+
|
|
62
91
|
## Common Workflows
|
|
63
92
|
|
|
64
93
|
### Workflow 1: Instagram Content Audit
|
|
@@ -67,7 +96,13 @@ Based on findings:
|
|
|
67
96
|
|
|
68
97
|
1. **Get All Posts**
|
|
69
98
|
```
|
|
70
|
-
|
|
99
|
+
execute("instagram", "user", "user_posts", {"user": "username", "count": 100})
|
|
100
|
+
→ returns cache_key + first page of results
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
If more posts exist (response includes `next_offset`):
|
|
104
|
+
```
|
|
105
|
+
get_page(cache_key, offset=next_offset, limit=50)
|
|
71
106
|
```
|
|
72
107
|
|
|
73
108
|
2. **Calculate Metrics**
|
|
@@ -78,9 +113,15 @@ For each post:
|
|
|
78
113
|
- Content type (Reel, carousel, single image, video)
|
|
79
114
|
```
|
|
80
115
|
|
|
116
|
+
Use `query_cache` to sort and filter:
|
|
117
|
+
```
|
|
118
|
+
query_cache(cache_key, sort_by="likes desc", aggregate="avg:likes,comments")
|
|
119
|
+
```
|
|
120
|
+
|
|
81
121
|
3. **Identify Top Performers**
|
|
82
122
|
```
|
|
83
|
-
|
|
123
|
+
query_cache(cache_key, sort_by="likes desc")
|
|
124
|
+
|
|
84
125
|
Top 10%: Analyze for common patterns
|
|
85
126
|
- Topics/themes
|
|
86
127
|
- Visual style
|
|
@@ -90,7 +131,9 @@ Top 10%: Analyze for common patterns
|
|
|
90
131
|
|
|
91
132
|
4. **Analyze Content Mix**
|
|
92
133
|
```
|
|
93
|
-
|
|
134
|
+
query_cache(cache_key, group_by="type", aggregate="count:id,avg:likes,avg:comments")
|
|
135
|
+
|
|
136
|
+
Results show:
|
|
94
137
|
- Reels: X% of posts, Y% of engagement
|
|
95
138
|
- Carousels: X% of posts, Y% of engagement
|
|
96
139
|
- Single images: X% of posts, Y% of engagement
|
|
@@ -99,7 +142,7 @@ Count by type:
|
|
|
99
142
|
5. **Benchmark Against Competitors**
|
|
100
143
|
```
|
|
101
144
|
For each competitor:
|
|
102
|
-
|
|
145
|
+
execute("instagram", "user", "user_posts", {"user": "competitor", "count": 50})
|
|
103
146
|
Compare:
|
|
104
147
|
- Posting frequency
|
|
105
148
|
- Engagement rates
|
|
@@ -107,6 +150,11 @@ Compare:
|
|
|
107
150
|
- Top themes
|
|
108
151
|
```
|
|
109
152
|
|
|
153
|
+
6. **Export Results**
|
|
154
|
+
```
|
|
155
|
+
export_data(cache_key, "csv")
|
|
156
|
+
```
|
|
157
|
+
|
|
110
158
|
**Expected Output**:
|
|
111
159
|
- Content performance report
|
|
112
160
|
- Top 10 performing posts
|
|
@@ -120,9 +168,17 @@ Compare:
|
|
|
120
168
|
|
|
121
169
|
1. **Collect Post History**
|
|
122
170
|
```
|
|
123
|
-
|
|
171
|
+
execute("linkedin", "user", "user_posts", {"urn": "fsd_profile:ACoAAA...", "count": 100})
|
|
172
|
+
→ returns cache_key + first page
|
|
124
173
|
```
|
|
125
174
|
|
|
175
|
+
For company page posts:
|
|
176
|
+
```
|
|
177
|
+
execute("linkedin", "company", "company_posts", {"urn": {"type": "company", "value": "1441"}, "count": 100})
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Use `get_page(cache_key, offset, limit)` if more posts exist.
|
|
181
|
+
|
|
126
182
|
2. **Categorize Content**
|
|
127
183
|
```
|
|
128
184
|
Group by type:
|
|
@@ -136,6 +192,8 @@ Group by type:
|
|
|
136
192
|
|
|
137
193
|
3. **Analyze Engagement by Type**
|
|
138
194
|
```
|
|
195
|
+
query_cache(cache_key, aggregate="avg:comment_count,avg:share_count", group_by="type")
|
|
196
|
+
|
|
139
197
|
For each content type:
|
|
140
198
|
- Average reactions
|
|
141
199
|
- Average comments
|
|
@@ -173,13 +231,16 @@ Calculate average engagement for each group
|
|
|
173
231
|
|
|
174
232
|
1. **Get Channel Videos**
|
|
175
233
|
```
|
|
176
|
-
|
|
234
|
+
execute("youtube", "channel", "channel_videos", {"channel": "channel_id", "count": 50})
|
|
235
|
+
→ returns cache_key + first page
|
|
177
236
|
```
|
|
178
237
|
|
|
238
|
+
Use `get_page(cache_key, offset, limit)` for additional videos.
|
|
239
|
+
|
|
179
240
|
2. **Analyze Each Video**
|
|
180
241
|
```
|
|
181
242
|
For each video:
|
|
182
|
-
|
|
243
|
+
execute("youtube", "video", "video", {"video": "video_id"})
|
|
183
244
|
|
|
184
245
|
Metrics:
|
|
185
246
|
- Views
|
|
@@ -190,6 +251,8 @@ Metrics:
|
|
|
190
251
|
|
|
191
252
|
3. **Identify Patterns**
|
|
192
253
|
```
|
|
254
|
+
query_cache(cache_key, sort_by="views desc")
|
|
255
|
+
|
|
193
256
|
Analyze top 20% by views:
|
|
194
257
|
- Video length
|
|
195
258
|
- Titles (keywords, style)
|
|
@@ -201,7 +264,7 @@ Analyze top 20% by views:
|
|
|
201
264
|
4. **Engagement Analysis**
|
|
202
265
|
```
|
|
203
266
|
Check comments:
|
|
204
|
-
|
|
267
|
+
execute("youtube", "video", "video_comments", {"video": "video_id", "count": 100})
|
|
205
268
|
|
|
206
269
|
Analyze:
|
|
207
270
|
- Comment quality
|
|
@@ -225,44 +288,49 @@ Compare:
|
|
|
225
288
|
- Title and thumbnail insights
|
|
226
289
|
- Upload strategy recommendations
|
|
227
290
|
|
|
228
|
-
## MCP Tools Reference
|
|
291
|
+
## MCP Tools Reference (v2)
|
|
229
292
|
|
|
230
293
|
### Instagram
|
|
231
|
-
- `
|
|
232
|
-
- `
|
|
233
|
-
- `
|
|
234
|
-
- `
|
|
294
|
+
- `execute("instagram", "user", "user_posts", {"user": username, "count": N})` - Get posts with engagement
|
|
295
|
+
- `execute("instagram", "post", "post", {"post": post_id})` - Get detailed post metrics
|
|
296
|
+
- `execute("instagram", "post", "post_likes", {"post": post_id, "count": N})` - Analyze likers
|
|
297
|
+
- `execute("instagram", "post", "post_comments", {"post": post_id, "count": N})` - Get comments
|
|
235
298
|
|
|
236
299
|
### LinkedIn
|
|
237
|
-
- `
|
|
238
|
-
- `
|
|
300
|
+
- `execute("linkedin", "user", "user_posts", {"urn": "fsd_profile:ACoAAA...", "count": N})` - Get user post history
|
|
301
|
+
- `execute("linkedin", "company", "company_posts", {"urn": {"type": "company", "value": "ID"}, "count": N})` - Company page posts
|
|
239
302
|
|
|
240
303
|
### Twitter/X
|
|
241
|
-
- `
|
|
242
|
-
- `
|
|
304
|
+
- `execute("twitter", "user", "user_posts", {"user": username, "count": N})` - Get tweets
|
|
305
|
+
- `execute("twitter", "search", "search_posts", {"query": query, "count": N})` - Find trending tweets
|
|
243
306
|
|
|
244
307
|
### YouTube
|
|
245
|
-
- `
|
|
246
|
-
- `
|
|
247
|
-
- `
|
|
308
|
+
- `execute("youtube", "channel", "channel_videos", {"channel": channel, "count": N})` - All videos
|
|
309
|
+
- `execute("youtube", "video", "video", {"video": video_id})` - Video details and metrics
|
|
310
|
+
- `execute("youtube", "video", "video_comments", {"video": video_id, "count": N})` - Comments
|
|
248
311
|
|
|
249
312
|
### Reddit
|
|
250
|
-
- `
|
|
251
|
-
- `
|
|
313
|
+
- `execute("reddit", "user", "user_posts", {"username": username, "count": N})` - User's posts
|
|
314
|
+
- `execute("reddit", "search", "search_posts", {"query": query, "count": N})` - Find popular posts
|
|
315
|
+
|
|
316
|
+
### Pagination & Analysis
|
|
317
|
+
- `get_page(cache_key, offset, limit)` - Fetch next page of results from any execute() call
|
|
318
|
+
- `query_cache(cache_key, conditions?, sort_by?, aggregate?, group_by?)` - Filter/sort/aggregate cached results
|
|
319
|
+
- `export_data(cache_key, "csv"|"json"|"jsonl")` - Export dataset as downloadable file
|
|
252
320
|
|
|
253
321
|
## Key Metrics
|
|
254
322
|
|
|
255
323
|
**Engagement Rate**:
|
|
256
|
-
- Formula: (Likes + Comments + Shares) / Followers
|
|
324
|
+
- Formula: (Likes + Comments + Shares) / Followers x 100
|
|
257
325
|
- Instagram benchmark: 3-6%
|
|
258
326
|
- LinkedIn benchmark: 2-5% of connections
|
|
259
327
|
- Twitter benchmark: 0.5-1%
|
|
260
328
|
|
|
261
329
|
**Content Performance Score**:
|
|
262
330
|
```
|
|
263
|
-
Score = (Engagement Rate
|
|
264
|
-
(Comments/Likes Ratio
|
|
265
|
-
(Share Rate
|
|
331
|
+
Score = (Engagement Rate x 40) +
|
|
332
|
+
(Comments/Likes Ratio x 30) +
|
|
333
|
+
(Share Rate x 30)
|
|
266
334
|
```
|
|
267
335
|
|
|
268
336
|
**Viral Potential Indicators**:
|
|
@@ -278,13 +346,13 @@ Score = (Engagement Rate × 40) +
|
|
|
278
346
|
- Key insights and patterns
|
|
279
347
|
- Recommendations for optimization
|
|
280
348
|
|
|
281
|
-
**CSV Export
|
|
349
|
+
**CSV Export** (via `export_data(cache_key, "csv")`):
|
|
282
350
|
- Post URL, date, type
|
|
283
351
|
- Likes, comments, shares
|
|
284
352
|
- Engagement rate
|
|
285
353
|
- Performance rank
|
|
286
354
|
|
|
287
|
-
**JSON Export
|
|
355
|
+
**JSON Export** (via `export_data(cache_key, "json")`):
|
|
288
356
|
- Full post data with metadata
|
|
289
357
|
- Time-series engagement data
|
|
290
358
|
- Historical trends
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: anysite-crm-account-brief
|
|
3
|
+
description: Pre-meeting brief for an account that lives in the connected CRM - what the CRM already knows (fields, contacts, history) merged with fresh outside data (funding, exec changes, news, key people's recent LinkedIn activity) into a one-page brief with talking points. Read-only. Use when the user preps for a call/meeting/demo with a CRM account or asks for account research in the context of their pipeline. Requires an active CRM connection - for briefs on arbitrary companies without CRM context, other research skills apply.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CRM Account Brief
|
|
7
|
+
|
|
8
|
+
One account, twenty minutes of research, one page the user can read in the elevator.
|
|
9
|
+
|
|
10
|
+
## Flow
|
|
11
|
+
|
|
12
|
+
### 1. CRM context (if connected)
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
crm_query_records(object_type="companies", search="<name or domain>")
|
|
16
|
+
crm_query_records(object_type="contacts", search="<domain>") # linked people
|
|
17
|
+
```
|
|
18
|
+
What we already know: fields, mapped scores/signals, who we talk to, what stage. The brief
|
|
19
|
+
must not contradict the CRM — where outside data disagrees (e.g. new title), flag it as
|
|
20
|
+
an update candidate for `anysite-crm-enrich`/`anysite-crm-champions`.
|
|
21
|
+
|
|
22
|
+
### 2. Company snapshot
|
|
23
|
+
|
|
24
|
+
- `execute crunchbase/search {keywords: name}` → alias → `crunchbase/company` →
|
|
25
|
+
funding history, `leadership_hires[]`, `news[]`, `layoffs[]`, employee range, investors.
|
|
26
|
+
- `execute linkedin/search/search_sql_companies {website: domain}` → description,
|
|
27
|
+
specialities, locations, employee_count.
|
|
28
|
+
|
|
29
|
+
### 3. What's happening now
|
|
30
|
+
|
|
31
|
+
- Hiring: `linkedin/search/search_jobs {company: [{"type": "company", "value": "<id>"}],
|
|
32
|
+
sort: "recent", count: 20}` (numeric id from the `fsd_company:<id>` URN) — what functions
|
|
33
|
+
they're growing (that's their current priorities, use in talking points).
|
|
34
|
+
- News: crunchbase `news[]` first (already fetched); add
|
|
35
|
+
`techmeme/stories/stories_search {keyword: "<name>", count: 5}` for tech companies.
|
|
36
|
+
- Employer sentiment (optional, for bigger companies): resolve the employer id first via
|
|
37
|
+
`glassdoor/companies/companies_search {company: "<name>", count: 1}` → then
|
|
38
|
+
`companies_ratings {company: <id>}`; `blind/companies/companies_reviews` — morale,
|
|
39
|
+
attrition themes. Use with care in messaging — background context, never a quoted opener.
|
|
40
|
+
|
|
41
|
+
### 4. The people in the room
|
|
42
|
+
|
|
43
|
+
For each known attendee / key CRM contact with linkedin_url:
|
|
44
|
+
```
|
|
45
|
+
execute linkedin/user/user {user: <url>} → role, tenure, background
|
|
46
|
+
execute linkedin/user/user_posts {urn, count: 10,
|
|
47
|
+
posted_after: <90 days ago>} → what they talk about
|
|
48
|
+
```
|
|
49
|
+
Caveat: `user` called with a URL may omit the `urn` in its response, and `user_posts`
|
|
50
|
+
accepts ONLY a URN. If the urn is missing, recover it via
|
|
51
|
+
`search_users {first_name, last_name, company_keywords, count: 3}` → pick the match →
|
|
52
|
+
use its urn. Posts are personalization gold: real interests, stated problems, conference
|
|
53
|
+
activity.
|
|
54
|
+
No posts ≠ no signal — check `user_comments` for lurker activity if it matters.
|
|
55
|
+
|
|
56
|
+
### 5. The brief
|
|
57
|
+
|
|
58
|
+
One page, this order:
|
|
59
|
+
1. **Snapshot** — what they do, size, stage, funding, trajectory (3 lines).
|
|
60
|
+
2. **What's new** — dated events (funding, hires, launches, layoffs), newest first.
|
|
61
|
+
3. **People** — attendees with one-line "who they are + what they care about".
|
|
62
|
+
4. **Angle** — 3 talking points tied to evidence, 1–2 risks/landmines (layoffs, churned
|
|
63
|
+
history in CRM, competitor relationship).
|
|
64
|
+
5. **Sources** — links for every claim. No link → don't claim it.
|
|
65
|
+
|
|
66
|
+
## Writes
|
|
67
|
+
|
|
68
|
+
None by default. If the user asks to save the brief: a note via the CRM UI is their
|
|
69
|
+
fastest path (note-writing is not exposed through crm_* tools); offer the brief as text
|
|
70
|
+
they can paste, or stamp mapped summary fields via `crm_upsert_companies` (dry-run first)
|
|
71
|
+
only if the profile maps them.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: anysite-crm-audit
|
|
3
|
+
description: Read-only data quality audit of the connected CRM - field completeness per mapped property, duplicate candidates, stale records, enrichability estimate. Produces a report and a concrete fix plan, never writes anything - run it first when you don't yet know what's broken; the actual fixing happens in anysite-crm-enrich. Use when the user asks "what's the state of my CRM", wants a data quality report, duplicate check, or a safe first run after connecting a CRM. Requires an active CRM connection.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CRM Audit
|
|
7
|
+
|
|
8
|
+
The safe first date with a user's CRM: read everything, write nothing, show what's broken
|
|
9
|
+
and what enrichment would fix. Also the natural funnel into `anysite-crm-enrich`.
|
|
10
|
+
|
|
11
|
+
## Prerequisites
|
|
12
|
+
|
|
13
|
+
Active CRM connection. No profile needed (works better with one — gap analysis follows the
|
|
14
|
+
mapped fields).
|
|
15
|
+
|
|
16
|
+
## Flow
|
|
17
|
+
|
|
18
|
+
### 1. Inventory
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
crm_get_schema(object_type="contacts") / (object_type="companies")
|
|
22
|
+
```
|
|
23
|
+
Use `properties` filtering when you only need specific fields — the full schema is large.
|
|
24
|
+
Then page through records:
|
|
25
|
+
```
|
|
26
|
+
crm_query_records(object_type=..., properties=[key fields], after=<cursor>)
|
|
27
|
+
```
|
|
28
|
+
Audit scope: whole portal if small; else the working list + a stated sample. Say which.
|
|
29
|
+
|
|
30
|
+
### 2. Analyze (all local — no further API calls)
|
|
31
|
+
|
|
32
|
+
- **Completeness:** % filled per mapped/target field (email, title, company, domain,
|
|
33
|
+
industry, size, linkedin_url). Rank by gap size.
|
|
34
|
+
- **Match-key coverage:** how many contacts have email / linkedin_url / neither (the
|
|
35
|
+
"neither" group is unenrichable and un-dedupable — flag it).
|
|
36
|
+
- **Duplicate candidates:** same normalized email; same domain with several company records;
|
|
37
|
+
same person name + company. Candidates only — never auto-merge.
|
|
38
|
+
- **Staleness:** if `anysite_last_enriched_at` (or similar) is mapped — age distribution;
|
|
39
|
+
contacts with no activity fields; companies with dead domains (spot-check a few via
|
|
40
|
+
`webparser/parse` only if the user asks).
|
|
41
|
+
- **Association health:** contacts without a company link (visible as missing company
|
|
42
|
+
fields when queried).
|
|
43
|
+
|
|
44
|
+
### 3. Report
|
|
45
|
+
|
|
46
|
+
Lead with the 3 numbers that matter: enrichable-now count, duplicate-candidate count,
|
|
47
|
+
unenrichable count. Then per-field completeness table, then the fix plan:
|
|
48
|
+
|
|
49
|
+
- "N contacts have linkedin_url but no title → `anysite-crm-enrich` fills them (~cost)"
|
|
50
|
+
- "N companies missing industry/size → enrich via company lookup (~cost)"
|
|
51
|
+
- "N duplicate candidates → list for manual review (merging is a CRM-side operation)"
|
|
52
|
+
|
|
53
|
+
Cost estimates come from the anysite-mcp source map (credits per call × volume). Offer to
|
|
54
|
+
run the enrichment as the next step — do not run it from this skill.
|
|
55
|
+
|
|
56
|
+
## Hard rule
|
|
57
|
+
|
|
58
|
+
This skill performs zero writes: no upserts, no dry-runs, no "small fixes". Its value is
|
|
59
|
+
that it is provably safe to run on day one.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: anysite-crm-champions
|
|
3
|
+
description: Detect job changes among CRM contacts (champion tracking) - find contacts who moved to a new company, flag past champions at new accounts, update the CRM and propose re-engagement plays. Widely considered the highest-converting B2B signal. Use specifically for job-change detection - "who changed jobs", "track champions", "are my contacts still there". For general field updates on contacts use anysite-crm-enrich instead. Requires an active CRM connection and contacts with linkedin_url or email.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CRM Champion Tracking
|
|
7
|
+
|
|
8
|
+
People move; CRMs rot (typically ~25%/year of contacts change jobs). A past champion at a
|
|
9
|
+
new company is warm pipeline. This skill finds the movers and turns them into plays.
|
|
10
|
+
|
|
11
|
+
## Prerequisites
|
|
12
|
+
|
|
13
|
+
Active CRM connection. Profile mapping for any writes — the Writing rules in
|
|
14
|
+
`anysite-crm-setup` apply, including its create policy: creating records here follows the
|
|
15
|
+
profile's `allow_create`, same as in `anysite-crm-prospect`. Contacts need `linkedin_url`
|
|
16
|
+
or `email` — run `anysite-crm-enrich` first if coverage is poor.
|
|
17
|
+
|
|
18
|
+
## Flow
|
|
19
|
+
|
|
20
|
+
### 1. Pick who to track
|
|
21
|
+
|
|
22
|
+
Priority order (ask the user which tier, default to the first available):
|
|
23
|
+
1. **Key champions** — closed-won contacts, power users, admins (if such a list/field exists),
|
|
24
|
+
2. **Open/closed-lost opportunity contacts**,
|
|
25
|
+
3. The working list / everyone with a linkedin_url.
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
crm_query_records(object_type="contacts", list_id=... | search=...,
|
|
29
|
+
properties=[record_id, email, linkedin_url, <company field>, jobtitle])
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Cap a run at ~100 contacts (one profile call each); more → propose batching by tier.
|
|
33
|
+
|
|
34
|
+
### 2. Detect moves
|
|
35
|
+
|
|
36
|
+
Per contact:
|
|
37
|
+
- `linkedin_url` → `execute linkedin/user/user {user: <url>}` → current experience.
|
|
38
|
+
- email only → `execute linkedin/email/email_sql_user {email}` → profile (live `email_user`
|
|
39
|
+
for the remainder).
|
|
40
|
+
|
|
41
|
+
Compare the profile's **current company** against the CRM company. Normalize before
|
|
42
|
+
comparing (legal suffixes, casing, known rebrands); when unsure, treat as "same" — false
|
|
43
|
+
move-alarms erode trust. Also catch **promotions** (same company, new title) — a secondary
|
|
44
|
+
but useful signal.
|
|
45
|
+
|
|
46
|
+
### 3. Classify and propose plays
|
|
47
|
+
|
|
48
|
+
- **Moved to an in-ICP company** → hottest: "past champion at new account" play. Propose:
|
|
49
|
+
update old record, create the new-company record and a fresh contact entry.
|
|
50
|
+
- **Moved out of ICP** → update CRM only.
|
|
51
|
+
- **Promoted** → update title; suggest congratulation touch if they're an active deal contact.
|
|
52
|
+
- **Profile gone/private** → report, no change.
|
|
53
|
+
|
|
54
|
+
### 4. Write back (with explicit user confirmation)
|
|
55
|
+
|
|
56
|
+
Job-change writes touch the fields most likely to collide with CRM automations, so always
|
|
57
|
+
dry-run and show the diff, even for small batches:
|
|
58
|
+
|
|
59
|
+
- Update the old contact: new title/company per profile mapping (these need `overwrite` in
|
|
60
|
+
the profile — job data is volatile by design).
|
|
61
|
+
- New account: `crm_upsert_companies` (match by domain, `allow_create` per profile).
|
|
62
|
+
- New email at the new company: try `user_email`; the higher-yield `find_email_by_url` may
|
|
63
|
+
be disabled in MCP — check `discover("linkedin", "user")` before promising it. Note that
|
|
64
|
+
creating a NEW contact record requires an email; without one, update the existing record.
|
|
65
|
+
- Association: pass `associate_company_domain` (or `associate_company_id` from the company
|
|
66
|
+
upsert result) so the contact links to the new company; the server keeps the old
|
|
67
|
+
association unless `overwrite_associations=true` — set it only if the user confirms the
|
|
68
|
+
contact should be re-linked.
|
|
69
|
+
|
|
70
|
+
Save `run_id`s; mention `crm_undo`.
|
|
71
|
+
|
|
72
|
+
### 5. Report
|
|
73
|
+
|
|
74
|
+
Table: contact → old → new → play. Lead with movers into ICP accounts. Include suggested
|
|
75
|
+
opener anchored on the shared history ("you used X at <old company>...") — personalization
|
|
76
|
+
from facts, never invented familiarity.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: anysite-crm-competitor-intel
|
|
3
|
+
description: Displacement hunting tied to the CRM - find companies using a competitor's product (Wappalyzer technographics), mine switching reasons and pains from software reviews (Capterra switched_from/switching_reason, TrustRadius, GetApp), cross-reference with CRM accounts and tag displacement targets. Use ONLY when the goal is a CRM-tied displacement list or competitor-user tagging. For general competitor strategy research (content, hiring, positioning, no CRM) use anysite-competitor-intelligence.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CRM Competitor Intel
|
|
7
|
+
|
|
8
|
+
Competitor-switch signals are the highest-intent plays in signal-based selling. This skill
|
|
9
|
+
builds the target list and the ammunition: who uses the competitor, and what their users
|
|
10
|
+
complain about.
|
|
11
|
+
|
|
12
|
+
## Prerequisites
|
|
13
|
+
|
|
14
|
+
Active CRM connection for the cross-reference/tagging part (Writing rules from
|
|
15
|
+
`anysite-crm-setup` apply to tagging). The research part works without one.
|
|
16
|
+
|
|
17
|
+
## Flow
|
|
18
|
+
|
|
19
|
+
### 1. Who uses the competitor (technographics)
|
|
20
|
+
|
|
21
|
+
Only works for competitors whose product is detectable on websites (martech, analytics,
|
|
22
|
+
chat widgets, ecommerce...):
|
|
23
|
+
```
|
|
24
|
+
execute wappalyzer/technologies {technology: "<competitor slug>"}
|
|
25
|
+
→ website_count (market size), top_websites[] (sample of users, with traffic/tech-spend),
|
|
26
|
+
alternatives[] (the category landscape), top_countries
|
|
27
|
+
```
|
|
28
|
+
Honest limitation: `top_websites` is a **sample**, not an exhaustive list. Frame it as
|
|
29
|
+
"examples + market sizing", supplement with `linkedin/search/search_sql_companies`
|
|
30
|
+
searching the competitor name in `specialities`/`description`, and with
|
|
31
|
+
`producthunt/products/products_alternatives` for the category graph.
|
|
32
|
+
|
|
33
|
+
Not website-detectable (e.g. a database vendor)? Skip to reviews and search: job posts
|
|
34
|
+
mentioning the tool (`linkedin/search/search_jobs {keywords: "<tool>"}` — companies whose
|
|
35
|
+
vacancies require competitor experience are its customers), reddit/community mentions.
|
|
36
|
+
|
|
37
|
+
### 2. What their users complain about (review mining)
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
execute capterra/products/products_search {query: "<competitor>", count: 5} → seo_id
|
|
41
|
+
execute capterra/products/products_reviews {product: "<seo_id>", count: 50}
|
|
42
|
+
```
|
|
43
|
+
The `product` param wants the `seo_id` field (not `id`). Reviews include `switched_from[]`,
|
|
44
|
+
`switching_reason` and `chosen_reason` — direct competitor-switch evidence, mine these
|
|
45
|
+
first. Same pattern via `trustradius` and `getapp` `products_reviews` (g2 exposes search
|
|
46
|
+
only). Filter low-rating reviews with `query_cache` (free), then extract with the LLM:
|
|
47
|
+
recurring pains, switching triggers, praised alternatives, verbatim quotes worth reusing.
|
|
48
|
+
Keep 3–7 pains with quote + source URL each — this is the personalization ammunition.
|
|
49
|
+
|
|
50
|
+
### 3. Cross-reference with the CRM
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
crm_query_records(object_type="companies", search=<domain from step 1>)
|
|
54
|
+
```
|
|
55
|
+
Split: already in CRM (mark as competitor-user) / net-new fits (candidates for
|
|
56
|
+
`anysite-crm-prospect`).
|
|
57
|
+
|
|
58
|
+
### 4. Tag and hand off
|
|
59
|
+
|
|
60
|
+
If the profile maps a field like `competitor_tool` / `displacement_target`:
|
|
61
|
+
```
|
|
62
|
+
crm_upsert_companies(records=[{domain: "<domain>", properties:{...}}], allow_create=false,
|
|
63
|
+
dry_run=true) → confirm → write
|
|
64
|
+
```
|
|
65
|
+
(Company upserts match only by domain.)
|
|
66
|
+
Report: market sizing, tagged accounts, pain library with quotes, and suggested play
|
|
67
|
+
("lead with <pain #1>, they're on <competitor> per <evidence>"). Evidence links always —
|
|
68
|
+
a displacement claim without a source is a guess, label it as such.
|
|
69
|
+
|
|
70
|
+
## Boundaries
|
|
71
|
+
|
|
72
|
+
- CRM-tied targeting lives here; broad competitor strategy analysis (content, hiring,
|
|
73
|
+
positioning) → `anysite-competitor-intelligence` skill.
|
|
74
|
+
- Net-new companies go through `anysite-crm-prospect` (dedup + create rules), not directly.
|