sales-prospecting
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSales Prospecting
销售线索挖掘
The prospecting hub. Always open with: "What's your goal?" and show the 7 sub-skills. Route, then run that sub-skill's recipe exactly. Every recipe below was live-tested — follow it, including the gotchas.
这是线索挖掘中心。启动时必须先问:“您的目标是什么?” 并展示7个子技能。根据用户选择引导至对应子技能,严格执行该子技能的操作流程。以下所有流程均经过实际测试——请严格遵循,包括注意事项。
Step 0: context (never blocks)
步骤0:上下文获取(不会阻塞流程)
- If or
config/gtm-config.mdexist in the working directory, read them for ICP, what you sell, buyer titles, customer list, and stack.config/persona-profile.md - If they don't exist, ask 1-2 quick questions inline ("Who do you sell to — industry, size, geo? Which titles buy?") or point the user at the icp-builder skill to build the config properly. A missing config must never block a run.
- Confirm the ask in one line before spending credits.
- 如果工作目录中存在或
config/gtm-config.md文件,请读取其中的ICP(理想客户画像)、销售产品、买方职位、客户列表以及技术栈信息。config/persona-profile.md - 如果文件不存在,可在线快速询问1-2个问题(例如“您的销售对象是哪些行业、规模、地域的企业?目标买方职位是什么?”),或者引导用户使用icp-builder技能来完善配置。缺失配置绝不能阻塞流程运行。
- 在消耗信用额度前,用一句话确认用户需求。
THE GOAL MENU (show this first)
目标菜单(首先展示)
- Find new companies — "I have an ICP, build me a fresh list"
- Lookalikes — "find companies like my best customers"
- Rank my accounts — "here are my accounts (book / territory / CSV) — who do I work first?"
- Event prospecting — "who's at <conference> that I should meet?"
- Expansion radar — "where can I grow inside my existing customers?"
- TAM builder — "how big is my market, with real numbers?"
- Champion tracker — "alert me when champions leave my customers" (live watcher)
- 挖掘新公司 —— “我已有ICP,请帮我生成一份全新的企业列表”
- 寻找相似企业 —— “寻找与我的最佳客户相似的企业”
- 客户账户排名 —— “这是我的客户账户列表(客户库/销售区域/CSV文件)——我应该优先跟进哪些?”
- 活动线索挖掘 —— “<会议>中有哪些参会者是我应该对接的?”
- 拓展雷达 —— “我可以在现有客户群体中拓展哪些业务?”
- TAM构建器 —— “我的市场规模有多大?需要真实数据支撑”
- 关键联系人追踪器 —— “当关键联系人离开客户公司时提醒我”(实时监控)
HOW EVERY SEARCH RUNS (Code Mode ground rules)
所有搜索的运行规则(代码模式基本准则)
All Crustdata data tools run inside — a plain-JavaScript script (author against the typed surface from , but write zero type annotations; a , , or generic is a parse error that fails the whole run before any spend).
execute({ code })get_schema: Typeas- Every script opens with a query comment — for the user's literal ask,
// user query: ...for a derived step. Scripts without one are rejected before running.// model query: ... - One I/O primitive: returns
const r = await callTool(name, params)or{ ok: true, data }. Always branch on{ ok: false, status, errorType, message }— a failed call does not abort the script, so an unchecked failure silently proceeds on empty data and looks like "no results".r.ok - is a response whitelist. The result carries only the groups/paths you list; an omitted group reads as
fieldslater and looks like missing data. List every group you read.undefined - Return the smallest projection. Only what the script returns reaches the model — map to name/id/url/signal rows, never raw profiles.
- Fan out independent calls with ; batch first with
await parallelMap(items, fn). Never parallelize cursor pagination or dependent stages.chunk(list, 25)after costly stages so a timeout returns partial progress.checkpoint(acc) - Categorical values are closed sets. A plausible-but-wrong value silently returns zero rows. Resolve exact stored values with /
company_autocomplete(free) before filtering:person_autocomplete,basic_info.industries,taxonomy.professional_network_industry,funding.last_round_type, titles, seniority, function_category.basic_info.company_type - Seniority vocabulary (person_search): ,
Entry Level,Entry Level Manager,Experienced Manager,Senior,Director,Vice President,CXO,Owner / Partner,In Training. Always confirm viaStrategicbefore filtering.person_autocomplete - Plan-gated projections fail the whole call with a 403 that names the field — drop it and re-run. Known: and
professional_network.followerson person_search. Never project followers; filter onmetadatainstead (professional_network.connectionsworks).gte(..., 100) - Filter paths ≠ response paths (person_search): filter → returns under
...current.company_name; filter...current[].name→ returns under...current.company_id; filter...current[].crustdata_company_id→ returns under...current.company_website_domain. The LinkedIn URL returns at...current[].company_website(use thesocial_handles.professional_network_identifier.profile_urlaccessor) and is not filterable.profileUrl(p) - Value formats: company accepts ISO-3 (
locations.country) as a filter but returns the normalized full name — don't compare a response value againstUSA. Employer HQ country is ISO-3; person"USA"is the full name (basic_profile.location.country); domains are bare (United States); funding stages are lowercase snake_case (stripe.com—series_a/inmatch the exact stored string,not_inis case-insensitive).= - Nested-array AND (person_search): a plain over one nested-array field (
and_) means one array element must satisfy every condition — so "an Engineer at company X" is the default and works. For cross-element ("was an Engineer at A and a Manager at B", two different jobs) a plainexperience.*returns nothing; use theand_group instead. The query builder has noall_ofhelper, so write the raw filter object:all_of. For several required values on one field,{ op: "all_of", conditions: [ {...}, {...} ] }does the same thing.has_all - Zero results ≠ no matches. A well-formed query can encode an ill-posed ask. Decompose, test each predicate's selectivity with cheap counts, and read the (per-call filters + counts) in the execute response before trusting multi-step results.
trajectory - Dedup across rounds with on person_search.
post_processing: { exclude_profiles: [...], exclude_names: [...] }
所有Crustdata数据工具均在中运行——这是一个纯JavaScript脚本(基于返回的类型接口编写,但无需添加任何类型注解;若出现、或泛型语法,会触发解析错误,导致流程在产生任何消耗前直接失败)。
execute({ code })get_schema: Typeas- 每个脚本必须以查询注释开头 —— 使用记录用户的原始需求,使用
// user query: ...记录衍生步骤。无注释的脚本会在运行前被拒绝。// model query: ... - 仅使用一种I/O原语:会返回
const r = await callTool(name, params)或{ ok: true, data }。必须始终根据{ ok: false, status, errorType, message }进行分支处理——调用失败不会终止脚本,若未检查失败状态,会导致流程基于空数据继续运行,最终呈现“无结果”的假象。r.ok - 是响应白名单。结果仅包含您列出的分组/路径;未列出的分组后续会被视为
fields,看起来像是数据缺失。请列出所有需要读取的分组。undefined - 返回最小化的投影结果。只有脚本返回的内容会传递给模型——映射为名称/ID/URL/信号行,绝不要返回原始配置文件。
- 使用并行处理独立调用;先通过
await parallelMap(items, fn)进行批量处理。绝不要对游标分页或依赖阶段进行并行处理。在高消耗阶段后调用chunk(list, 25),这样超时后仍能返回部分进度。checkpoint(acc) - 分类值是封闭集合。看似合理但错误的值会静默返回零行数据。在过滤前,使用/
company_autocomplete(免费工具)确认精确的存储值:例如person_autocomplete、basic_info.industries、taxonomy.professional_network_industry、funding.last_round_type、职位头衔、职级、职能类别。basic_info.company_type - 职级词汇(person_search):、
Entry Level、Entry Level Manager、Experienced Manager、Senior、Director、Vice President、CXO、Owner / Partner、In Training。过滤前必须通过Strategic确认。person_autocomplete - 受计划限制的投影会导致整个调用失败并返回403错误,错误信息会指明对应的字段——请移除该字段后重新运行。已知受限字段:中的
person_search和professional_network.followers。绝不要投影followers字段;可改用metadata进行过滤(professional_network.connections有效)。gte(..., 100) - 过滤路径≠响应路径(person_search):过滤→ 返回值位于
...current.company_name;过滤...current[].name→ 返回值位于...current.company_id;过滤...current[].crustdata_company_id→ 返回值位于...current.company_website_domain。LinkedIn URL返回于...current[].company_website(使用social_handles.professional_network_identifier.profile_url访问器),且不可用于过滤。profileUrl(p) - 值格式:企业作为过滤器时接受ISO-3格式(如
locations.country),但返回值为标准化全称——不要将返回值与USA进行比较。雇主总部国家为ISO-3格式;个人"USA"为全称(如basic_profile.location.country);域名是裸域名(如United States);融资阶段为小写蛇形命名(如stripe.com——series_a/in匹配精确存储字符串,not_in不区分大小写)。= - 嵌套数组AND逻辑(person_search):对单个嵌套数组字段(如)使用普通
experience.*意味着数组中至少有一个元素满足所有条件——因此“在X公司任职的工程师”是默认逻辑,可正常工作。对于跨元素的逻辑(如“曾在A公司任工程师,且在B公司任经理”,两个不同职位),普通and_会返回空结果;需改用and_分组。查询构建器没有all_of辅助函数,因此需编写原始过滤对象:all_of。对于单个字段的多个必填值,{ op: "all_of", conditions: [ {...}, {...} ] }可实现相同效果。has_all - 零结果≠无匹配项。格式正确的查询可能隐含不合理的需求。请分解查询,用低成本的计数测试每个谓词的筛选性,并在信任多步骤结果前,查看execute响应中的(每次调用的过滤器+计数)。
trajectory - 通过在多轮搜索中去重(仅适用于person_search)。
post_processing: { exclude_profiles: [...], exclude_names: [...] }
SUB-SKILL RECIPES
子技能操作流程
1. Find new companies (net-new)
1. 挖掘新公司(全新线索)
Intake: ICP (industry/size/geo/stage) + signals (palette below) + target titles + rows wanted.
Step 1 — validate every categorical via autocomplete. Wrong value = silent zero.
js
// model query: resolve exact industry and funding-stage values before filtering
const probes = [
["basic_info.industries", "software"],
["funding.last_round_type", "series a"],
];
const values = await parallelMap(probes, async ([field, query]) => {
const r = await callTool("company_autocomplete", { field, query });
return { field, values: r.ok ? r.data : r.message };
});
return values;Step 2 — broad , then inspect top 10 and refine 2-4 rounds. Refinement levers: stage lock (), amount band (, ), , growth floor — filterable but not sortable; to rank by growth, filter on it and sort on or . Report what each round caught and dropped.
company_searchfunding.last_round_typefunding.total_investment_usdfunding.last_round_amount_usdbasic_info.year_foundedgt("headcount.growth_percent.12m", N)headcount.totalfunding.last_fundraise_datejs
// model query: US software companies 51-1000, raised $5M+, growing >20% — refine round 2
const r = await callTool("company_search", {
filters: and_(
in_("basic_info.industries", ["Software Development"]),
eq("locations.country", "USA"),
between("headcount.total", 51, 1000),
gt("funding.total_investment_usd", 5000000),
gt("headcount.growth_percent.12m", 20)
),
fields: ["crustdata_company_id", "basic_info", "headcount", "funding"],
sorts: [{ field: "funding.last_fundraise_date", order: "desc" }],
limit: 25,
});
if (!r.ok) return { error: r.message };
return {
total: r.data.total_count,
rows: r.data.companies.map(c => ({
id: c.crustdata_company_id,
name: c.basic_info?.name,
domain: c.basic_info?.primary_domain,
hc: c.headcount?.total,
growth12m: c.headcount?.growth_percent?.["12m"],
lastRound: c.funding?.last_round_type,
lastRaise: c.funding?.last_fundraise_date,
})),
};Step 3 — people pull. One scoped to the shortlisted company ids + target titles/seniority (resolve seniority values via first). Junk filter in the same query: connections floor, advisor/investor exclusion ( builds one fuzzy negation per value — AND several).
person_searchperson_autocompleteexcludes()js
// model query: buyer-title people at the shortlisted companies
const r = await callTool("person_search", {
filters: and_(
in_("experience.employment_details.current.company_id", inputs.ids),
in_("experience.employment_details.current.seniority_level", ["Director", "Vice President", "CXO"]),
gte("professional_network.connections", 100),
excludes("experience.employment_details.current.title", "advisor"),
excludes("experience.employment_details.current.title", "investor")
),
fields: ["basic_profile", "experience", "social_handles"],
limit: 50,
});
if (!r.ok) return { error: r.message };
return r.data.profiles.map(p => ({
name: p.basic_profile?.name,
title: p.basic_profile?.current_title,
company: p.experience?.employment_details?.current?.[0]?.name,
url: profileUrl(p),
}));Step 4 — score FIT x TIMING x WARMTH → 🔥/🟡/⚪ with the driving signal + its date shown on every row. Free data only; contact enrichment stays opt-in (see universal rules).
输入:ICP(行业/规模/地域/阶段) + 信号指标(如下方可选列表) + 目标职位头衔 + 所需结果行数。
步骤1 —— 通过autocomplete验证所有分类值。错误值会导致静默返回零行数据。
js
// model query: resolve exact industry and funding-stage values before filtering
const probes = [
["basic_info.industries", "software"],
["funding.last_round_type", "series a"],
];
const values = await parallelMap(probes, async ([field, query]) => {
const r = await callTool("company_autocomplete", { field, query });
return { field, values: r.ok ? r.data : r.message };
});
return values;步骤2 —— 先进行宽泛的,再查看前10条结果并进行2-4轮优化。优化手段:锁定融资阶段()、融资金额区间(、)、、最低增长率——该字段可过滤但不可排序;若要按增长率排名,需先过滤再按或排序。需报告每一轮筛选保留和排除的内容。
company_searchfunding.last_round_typefunding.total_investment_usdfunding.last_round_amount_usdbasic_info.year_foundedgt("headcount.growth_percent.12m", N)headcount.totalfunding.last_fundraise_datejs
// model query: US software companies 51-1000, raised $5M+, growing >20% — refine round 2
const r = await callTool("company_search", {
filters: and_(
in_("basic_info.industries", ["Software Development"]),
eq("locations.country", "USA"),
between("headcount.total", 51, 1000),
gt("funding.total_investment_usd", 5000000),
gt("headcount.growth_percent.12m", 20)
),
fields: ["crustdata_company_id", "basic_info", "headcount", "funding"],
sorts: [{ field: "funding.last_fundraise_date", order: "desc" }],
limit: 25,
});
if (!r.ok) return { error: r.message };
return {
total: r.data.total_count,
rows: r.data.companies.map(c => ({
id: c.crustdata_company_id,
name: c.basic_info?.name,
domain: c.basic_info?.primary_domain,
hc: c.headcount?.total,
growth12m: c.headcount?.growth_percent?.["12m"],
lastRound: c.funding?.last_round_type,
lastRaise: c.funding?.last_fundraise_date,
})),
};步骤3 —— 获取联系人信息。通过一次筛选入围企业ID对应的目标职位/职级(先通过确认职级值)。在同一查询中添加无效数据过滤规则:最低联系人数量、排除顾问/投资者(为每个值构建一个模糊否定条件——需同时添加多个)。
person_searchperson_autocompleteexcludes()js
// model query: buyer-title people at the shortlisted companies
const r = await callTool("person_search", {
filters: and_(
in_("experience.employment_details.current.company_id", inputs.ids),
in_("experience.employment_details.current.seniority_level", ["Director", "Vice President", "CXO"]),
gte("professional_network.connections", 100),
excludes("experience.employment_details.current.title", "advisor"),
excludes("experience.employment_details.current.title", "investor")
),
fields: ["basic_profile", "experience", "social_handles"],
limit: 50,
});
if (!r.ok) return { error: r.message };
return r.data.profiles.map(p => ({
name: p.basic_profile?.name,
title: p.basic_profile?.current_title,
company: p.experience?.employment_details?.current?.[0]?.name,
url: profileUrl(p),
}));步骤4 —— FIT × TIMING × WARMTH评分 → 用🔥/🟡/⚪标识,每行显示驱动评分的信号指标及其日期。仅使用免费数据;联系人信息补充需用户主动选择(参见通用规则)。
2. Lookalikes
2. 寻找相似企业
- the seed customers — free; one identifier type per call (
company_identifyORdomains, as arrays). Identify is fuzzy: one domain can match several companies — pick the topnamesmatch per identifier.confidence_score - ONE with
company_searchto read their shared traits (industry values, size band, stage, growth, geo).in_("crustdata_company_id", seedIds)
js
// model query: resolve seed customers and read the traits they share
const idr = await callTool("company_identify", {
domains: inputs.seedDomains,
fields: ["crustdata_company_id", "basic_info"],
});
if (!idr.ok) return { error: idr.message };
const ids = idr.data
.map(m => m.matches?.[0]?.company_data?.crustdata_company_id)
.filter(Boolean);
const r = await callTool("company_search", {
filters: in_("crustdata_company_id", ids),
fields: ["crustdata_company_id", "basic_info", "headcount", "funding", "taxonomy", "locations"],
limit: ids.length,
});
if (!r.ok) return { error: r.message };
return r.data.companies.map(c => ({
name: c.basic_info?.name,
industries: c.basic_info?.industries,
hc: c.headcount?.total,
growth12m: c.headcount?.growth_percent?.["12m"],
stage: c.funding?.last_round_type,
country: c.locations?.country,
}));- Those shared traits become the filters → run recipe 1 from step 2. Exclude the seeds and existing customers with .
nin_("crustdata_company_id", excludeIds)
- 使用识别种子客户——免费;每次调用仅使用一种标识符类型(
company_identify或domains,以数组形式传入)。识别是模糊匹配:一个域名可能匹配多个企业——为每个标识符选择names最高的匹配结果。confidence_score - 通过一次,使用
company_search读取种子客户的共同特征(行业值、规模区间、融资阶段、增长率、地域)。in_("crustdata_company_id", seedIds)
js
// model query: resolve seed customers and read the traits they share
const idr = await callTool("company_identify", {
domains: inputs.seedDomains,
fields: ["crustdata_company_id", "basic_info"],
});
if (!idr.ok) return { error: idr.message };
const ids = idr.data
.map(m => m.matches?.[0]?.company_data?.crustdata_company_id)
.filter(Boolean);
const r = await callTool("company_search", {
filters: in_("crustdata_company_id", ids),
fields: ["crustdata_company_id", "basic_info", "headcount", "funding", "taxonomy", "locations"],
limit: ids.length,
});
if (!r.ok) return { error: r.message };
return r.data.companies.map(c => ({
name: c.basic_info?.name,
industries: c.basic_info?.industries,
hc: c.headcount?.total,
growth12m: c.headcount?.growth_percent?.["12m"],
stage: c.funding?.last_round_type,
country: c.locations?.country,
}));- 将这些共同特征作为过滤器 → 从步骤2开始执行流程1。通过排除种子客户和现有客户。
nin_("crustdata_company_id", excludeIds)
3. Rank my accounts (book, territory, or pasted CSV — one sub-skill)
3. 客户账户排名(客户库、销售区域或粘贴的CSV文件——单个子技能)
Input: account names/domains/CSV from anywhere.
- Resolve ALL rows via (free; batch with
company_identify+chunk(domains, 25); one identifier type per call). Flag unresolved rows honestly — never silently drop them. Fuzzy matches multiply; pick topparallelMapper row.confidence_score - ONE with
company_search,in_("crustdata_company_id", ids). Growth returns inside thefields: ["crustdata_company_id", "basic_info", "funding", "headcount"]group (headcount) — no extra call needed. Rememberheadcount.growth_percent.{1m,3m,6m,12m}is a whitelist: list every group you read.fields
js
// user query: rank my account list — who do I work first?
const batches = chunk(inputs.domains, 25);
const identified = await parallelMap(batches, async (batch) => {
const r = await callTool("company_identify", {
domains: batch,
fields: ["crustdata_company_id", "basic_info"],
});
return r.ok ? r.data : batch.map(d => ({ matched_on: d, matches: [], error: r.message }));
});
const rows = identified.flat();
const unresolved = rows.filter(m => !m.matches?.length).map(m => m.matched_on);
const ids = rows.map(m => m.matches?.[0]?.company_data?.crustdata_company_id).filter(Boolean);
checkpoint({ ids, unresolved });
const r = await callTool("company_search", {
filters: in_("crustdata_company_id", ids),
fields: ["crustdata_company_id", "basic_info", "funding", "headcount"],
limit: ids.length,
});
if (!r.ok) return { error: r.message, unresolved };
return {
unresolved,
accounts: r.data.companies.map(c => ({
id: c.crustdata_company_id,
name: c.basic_info?.name,
lastRound: c.funding?.last_round_type,
lastRaise: c.funding?.last_fundraise_date,
raisedUsd: c.funding?.total_investment_usd,
hc: c.headcount?.total,
growth3m: c.headcount?.growth_percent?.["3m"],
growth12m: c.headcount?.growth_percent?.["12m"],
})),
};- Optional depth per hot account: with
job_search+aggregationsfor open-role counts (cheap hiring signal — see expansion radar for the snippet).limit: 0 - Score: TIMING-weighted. Funding <3mo = 🔥; 3-9mo = 🟡; >12mo = ⚪; headcount growth or a hiring surge bumps a tier. Output: ranked table + "why" per row + this week's top 5.
输入:来自任意渠道的企业名称/域名/CSV文件。
- 通过解析所有行——免费;通过
company_identify+chunk(domains, 25)进行批量处理;每次调用仅使用一种标识符类型。如实标记未解析的行——绝不要静默丢弃。模糊匹配会产生多个结果;为每行选择parallelMap最高的匹配项。confidence_score - 通过一次,使用
company_search,in_("crustdata_company_id", ids)。增长率数据包含在fields: ["crustdata_company_id", "basic_info", "funding", "headcount"]分组中(headcount)——无需额外调用。请记住headcount.growth_percent.{1m,3m,6m,12m}是白名单:列出所有需要读取的分组。fields
js
// user query: rank my account list — who do I work first?
const batches = chunk(inputs.domains, 25);
const identified = await parallelMap(batches, async (batch) => {
const r = await callTool("company_identify", {
domains: batch,
fields: ["crustdata_company_id", "basic_info"],
});
return r.ok ? r.data : batch.map(d => ({ matched_on: d, matches: [], error: r.message }));
});
const rows = identified.flat();
const unresolved = rows.filter(m => !m.matches?.length).map(m => m.matched_on);
const ids = rows.map(m => m.matches?.[0]?.company_data?.crustdata_company_id).filter(Boolean);
checkpoint({ ids, unresolved });
const r = await callTool("company_search", {
filters: in_("crustdata_company_id", ids),
fields: ["crustdata_company_id", "basic_info", "funding", "headcount"],
limit: ids.length,
});
if (!r.ok) return { error: r.message, unresolved };
return {
unresolved,
accounts: r.data.companies.map(c => ({
id: c.crustdata_company_id,
name: c.basic_info?.name,
lastRound: c.funding?.last_round_type,
lastRaise: c.funding?.last_fundraise_date,
raisedUsd: c.funding?.total_investment_usd,
hc: c.headcount?.total,
growth3m: c.headcount?.growth_percent?.["3m"],
growth12m: c.headcount?.growth_percent?.["12m"],
})),
};- 可选:针对高优先级账户进行深度分析:使用并结合
job_search+aggregations获取空缺职位数量(低成本招聘信号——参见拓展雷达中的代码片段)。limit: 0 - 评分:以TIMING(时机)为权重。融资时间<3个月=🔥;3-9个月=🟡;>12个月=⚪;员工人数增长或招聘激增可提升一个等级。输出:排名表格 + 每行的评分依据 + 本周Top5高优先级账户。
4. Event prospecting
4. 活动线索挖掘
- Source the roster for real — never invent attendees. for "<event> sponsors exhibitors" (the official /sponsors page usually lists tiers right in the snippet), then
web_search_livethe page for the full list. Rep-provided lists welcome.web_enrich_live
js
// model query: find the official sponsor page for the event and pull the roster
const s = await callTool("web_search_live", { query: `${inputs.event} sponsors exhibitors` });
if (!s.ok) return { error: s.message };
const page = s.data.results.find(x => /sponsor|exhibitor/i.test(x.url));
if (!page) return { candidates: s.data.results.map(x => ({ title: x.title, url: x.url })) };
const f = await callTool("web_enrich_live", { urls: [page.url] });
if (!f.ok) return { error: f.message };
return { url: page.url, page: f.data };- the roster (free,
company_identify+chunk(25)) → one scopedparallelMapto filter to ICP → people via recipe 1 step 3. Prefer people already posting about the event:company_searchon the event name — 1 credit per post (3 withsocial_post_search_live), so setexact_keyword_matchdeliberately (10-20).limit - Deliverable: meet-list ranked by ICP fit, with booth/tier + a suggested opener referencing the event (write it under the no-slop rule below).
- 真实获取参会名单——绝不虚构参会者。使用搜索“<活动名称> sponsors exhibitors”(官方/sponsors页面通常会在摘要中列出赞助商层级),然后使用
web_search_live抓取该页面获取完整名单。也可使用销售代表提供的名单。web_enrich_live
js
// model query: find the official sponsor page for the event and pull the roster
const s = await callTool("web_search_live", { query: `${inputs.event} sponsors exhibitors` });
if (!s.ok) return { error: s.message };
const page = s.data.results.find(x => /sponsor|exhibitor/i.test(x.url));
if (!page) return { candidates: s.data.results.map(x => ({ title: x.title, url: x.url })) };
const f = await callTool("web_enrich_live", { urls: [page.url] });
if (!f.ok) return { error: f.message };
return { url: page.url, page: f.data };- 使用解析名单——免费,通过
company_identify+chunk(25)批量处理 → 进行一次范围限定的parallelMap筛选符合ICP的企业 → 通过流程1的步骤3获取联系人信息。优先选择已发布活动相关内容的联系人:使用company_search搜索活动名称——每条帖子消耗1个信用额度(开启social_post_search_live时为3个),因此需合理设置exact_keyword_match(10-20)。limit - 交付物:按ICP匹配度排名的对接名单,包含展位/赞助商层级 + 参考活动的建议开场白(遵循下方“无冗余”规则撰写)。
5. Expansion radar (revenue hiding in plain sight)
5. 拓展雷达(隐藏在眼前的营收机会)
Input: customer list (CRM export or rep-provided). Sweep FOUR expansion surfaces — three scoped searches cover the whole book, not one call per account:
- New money — the rank-my-accounts scoped (funding fields): fresh raise = budget.
company_search - New people — ONE with
person_search+ senior levels; readin_("experience.employment_details.current.company_id", customerIds)and keep the last ~6 months. A new exec in the function you sell to is the single best expansion trigger. Also:current[].start_dateopenings (below).job_search - New ground — teams/geos/functions you don't touch yet: same scoped grouped by
person_search/ region in-script, compared against where your current contacts sit.function_category - Warm paths — your champions there + who they can intro (the referral ask, scripted). Feed from the config customer list and champion-tracker output.
js
// model query: new senior hires in the last 6 months across customer accounts
const cutoff = new Date(Date.now() - 183 * 24 * 3600 * 1000).toISOString().slice(0, 10);
const r = await callTool("person_search", {
filters: and_(
in_("experience.employment_details.current.company_id", inputs.customerIds),
in_("experience.employment_details.current.seniority_level", ["Director", "Vice President", "CXO"])
),
fields: ["basic_profile", "experience", "social_handles"],
limit: 100,
});
if (!r.ok) return { error: r.message };
return r.data.profiles.map(p => {
const cur = p.experience?.employment_details?.current?.[0];
return {
name: p.basic_profile?.name,
title: cur?.title,
company: cur?.name,
started: cur?.start_date,
url: profileUrl(p),
};
}).filter(x => x.started && x.started >= cutoff);js
// model query: open-role counts per customer account (hiring signal, counts only)
const r = await callTool("job_search", {
filters: in_("company.basic_info.company_id", inputs.customerIds),
aggregations: [{ type: "group_by", field: "company.basic_info.crustdata_company_id", agg: "count", size: 100 }],
limit: 0,
});
if (!r.ok) return { error: r.message };
return r.data.aggregations;Tech-stack detection in postings: filter with (exact token) for a brand/product/tech name — is typo-tolerant and matches lookalike words, so keep it only for descriptive multi-word matching. Sort postings by for freshness.
content.description[.](.)metadata.date_addedOutput per customer: opportunity — surface — evidence (dated) — estimated size (seats/teams) — the warm path in — suggested play. Rank the whole book by expansion-readiness.
输入:客户列表(CRM导出或销售代表提供)。扫描四个拓展维度——三次范围限定的搜索即可覆盖全部客户,无需为每个客户单独调用:
- 新增资金——客户账户排名流程中的范围限定(融资字段):最新融资=预算充足。
company_search - 新增人员——一次,使用
person_search+ 高级别职级;读取in_("experience.employment_details.current.company_id", customerIds)并保留最近约6个月的数据。您销售对接的职能部门新增高管是最佳拓展触发因素之一。此外:通过current[].start_date获取空缺职位(如下方代码)。job_search - 新业务场景——您尚未覆盖的团队/地域/职能:通过同一范围限定的,在脚本中按
person_search/地区分组,与您当前对接的联系人分布进行对比。function_category - 熟人间介——客户方的关键联系人 + 他们可以引荐的对象(引荐请求,已脚本化)。数据来自配置文件中的客户列表和关键联系人追踪器的输出。
js
// model query: new senior hires in the last 6 months across customer accounts
const cutoff = new Date(Date.now() - 183 * 24 * 3600 * 1000).toISOString().slice(0, 10);
const r = await callTool("person_search", {
filters: and_(
in_("experience.employment_details.current.company_id", inputs.customerIds),
in_("experience.employment_details.current.seniority_level", ["Director", "Vice President", "CXO"])
),
fields: ["basic_profile", "experience", "social_handles"],
limit: 100,
});
if (!r.ok) return { error: r.message };
return r.data.profiles.map(p => {
const cur = p.experience?.employment_details?.current?.[0];
return {
name: p.basic_profile?.name,
title: cur?.title,
company: cur?.name,
started: cur?.start_date,
url: profileUrl(p),
};
}).filter(x => x.started && x.started >= cutoff);js
// model query: open-role counts per customer account (hiring signal, counts only)
const r = await callTool("job_search", {
filters: in_("company.basic_info.company_id", inputs.customerIds),
aggregations: [{ type: "group_by", field: "company.basic_info.crustdata_company_id", agg: "count", size: 100 }],
limit: 0,
});
if (!r.ok) return { error: r.message };
return r.data.aggregations;职位发布中的技术栈检测:使用(精确匹配)过滤中的品牌/产品/技术名称——允许拼写错误,会匹配相似词汇,因此仅在描述性多词匹配时使用。按对职位发布进行排序以获取最新信息。
[.]content.description(.)metadata.date_added每个客户的输出内容:机会类型 —— 拓展维度 —— 证据(带日期) —— 预估规模(席位/团队) —— 熟人间介路径 —— 建议行动方案。按拓展就绪度对全部客户进行排名。
6. TAM builder (researched methodology — do it properly)
6. TAM构建器(经过验证的方法——请严格执行)
Bottom-up with real company counts beats top-down guessing (count actual companies x ACV). Build THREE layers, each = one count query: , read , ~0.03 credits each — cheap enough to run every breakdown you want. Note: has no parameter; + IS the count query. ( does have , mutually exclusive with .)
company_searchlimit: 1total_countcompany_searchcountlimit: 1total_countperson_searchcountlimit- TAM — broadest qualifying definition (anyone who could ever buy). Tested example: US "Software Development", headcount 51-1000 = 8,244.
- SAM — what your product/GTM serves today (add funding/stage/geo constraints). Tested: + raised $5M+ = 3,132. (+ growth >20%/12m narrows to 1,245 — a useful "SAM, growing" cut.)
- SOM — realistically winnable: SAM x a credible win-rate %, or capacity (reps x deals/yr).
js
// user query: how big is my market — TAM/SAM with real counts
const base = [
in_("basic_info.industries", ["Software Development"]),
eq("locations.country", "USA"),
between("headcount.total", 51, 1000),
];
const layers = [
{ name: "TAM", extra: [] },
{ name: "SAM", extra: [gt("funding.total_investment_usd", 5000000)] },
{ name: "SAM-growing", extra: [gt("funding.total_investment_usd", 5000000), gt("headcount.growth_percent.12m", 20)] },
];
const counts = await parallelMap(layers, async (l) => {
const r = await callTool("company_search", {
filters: and_(...base, ...l.extra),
fields: ["crustdata_company_id"],
limit: 1,
});
return { layer: l.name, count: r.ok ? r.data.total_count : null, error: r.ok ? undefined : r.message };
});
return counts;Then: $ = counts x ACV (ACV from config or the rep). Cross-check top-down: for analyst market-size figures and show both numbers side by side. State your filters — always print the exact filter set behind each count so the number is defensible. Offer breakdowns (by size band / geo / stage) as extra count queries; at ~0.03 credits each, run them freely via .
web_search_liveparallelMap基于真实企业数量的自下而上统计优于自上而下的猜测(实际企业数量 × ACV(年度合同价值))。构建三个层级,每个层级对应一次计数查询:,读取,每次约消耗0.03个信用额度——成本极低,可按需运行任意细分统计。注意:没有参数; + 即为计数查询。(有参数,与互斥。)
company_searchlimit: 1total_countcompany_searchcountlimit: 1total_countperson_searchcountlimit- TAM——最宽泛的合格定义(所有可能购买的企业)。测试示例:美国“软件开发”行业,员工人数51-1000人 = 8,244家。
- SAM——您的产品/GTM(上市策略)当前服务的范围(添加融资/阶段/地域限制)。测试示例:+ 融资≥500万美元 = 3,132家。(+ 12个月增长率>20%可缩小至1,245家——这是一个有用的“增长型SAM”细分。)
- SOM——实际可获取的市场:SAM × 可信的赢单率,或产能(销售代表数量 × 年成交数)。
js
// user query: how big is my market — TAM/SAM with real counts
const base = [
in_("basic_info.industries", ["Software Development"]),
eq("locations.country", "USA"),
between("headcount.total", 51, 1000),
];
const layers = [
{ name: "TAM", extra: [] },
{ name: "SAM", extra: [gt("funding.total_investment_usd", 5000000)] },
{ name: "SAM-growing", extra: [gt("funding.total_investment_usd", 5000000), gt("headcount.growth_percent.12m", 20)] },
];
const counts = await parallelMap(layers, async (l) => {
const r = await callTool("company_search", {
filters: and_(...base, ...l.extra),
fields: ["crustdata_company_id"],
limit: 1,
});
return { layer: l.name, count: r.ok ? r.data.total_count : null, error: r.ok ? undefined : r.message };
});
return counts;然后:市场规模 = 企业数量 × ACV(ACV来自配置文件或销售代表提供的数据)。与自上而下的数据交叉验证:使用获取分析师发布的市场规模数据,并将两组数据并列展示。明确您的筛选条件——始终打印每个计数背后的精确过滤器,确保数据可辩护。可提供细分统计(按规模区间/地域/融资阶段)作为额外的计数查询;每次约消耗0.03个信用额度,可通过自由运行。
web_search_liveparallelMap7. Champion tracker (list now + watcher forever)
7. 关键联系人追踪器(当前列表 + 永久监控)
Step 1 — the list today. with past employer + :
person_searchrecently_changed_jobsjs
// user query: champions who recently left my customer accounts
const r = await callTool("person_search", {
filters: and_(
in_("experience.employment_details.past.company_website_domain", inputs.customerDomains),
eq("recently_changed_jobs", true),
gte("professional_network.connections", 100),
excludes("experience.employment_details.past.title", "advisor"),
excludes("experience.employment_details.past.title", "investor"),
excludes("experience.employment_details.past.title", "board")
),
fields: ["basic_profile", "experience", "social_handles"],
limit: 50,
});
if (!r.ok) return { error: r.message };
return r.data.profiles.map(p => {
const cur = p.experience?.employment_details?.current?.[0];
const past = p.experience?.employment_details?.past?.[0];
return {
name: p.basic_profile?.name,
was: past?.title,
at: past?.name,
now: cur?.title,
nowAt: cur?.name,
landed: cur?.start_date,
url: profileUrl(p),
};
});Gotchas (all live-tested):
- is NOT filterable — don't try. The supported recipe is past employer +
experience.employment_details.past.end_date, then readrecently_changed_jobs = trueand curate.current[].start_date - The raw list is noisy — read the rows and drop: internal movers whose "new" company is still the customer (or its rebrand); subsidiary/acquisition moves (the entity was renamed or absorbed, nobody actually left); advisors/investors/LPs whose stint ended long ago; stale alumni whose recent job change has nothing to do with the customer — confirm the customer was their most recent employer before pitching "congrats".
- catches most advisor/investor titles up front; one value per condition, AND several. Reading the rows catches the rest.
excludes() - The new company reads from (you filter on
current[].name; the response key iscompany_name).name - Keep the connections floor; never project followers.
Step 2 — the watcher (keeps it running). Watchers are plain REST, not Code Mode. The Person Discovery Watcher turns exactly the filters you just validated into a continuous feed that delivers only NEW matches per run, weekly, to a webhook of your choice. First run = free baseline (up to 5 matches), then 0.5 credits per new person.
Process: run the Step 1 search first and confirm the list looks right with the user → build the curl with the SAME filters → show it → create only on an explicit yes.
bash
curl -X POST https://api.crustdata.com/watch/person/search \
-H "authorization: Bearer YOUR_API_KEY" \
-H "x-api-version: 2025-11-01" \
-H "content-type: application/json" \
-d '{
"filters": {
"op": "and",
"conditions": [
{ "field": "experience.employment_details.past.company_website_domain", "type": "in", "value": ["customer1.com", "customer2.com"] },
{ "field": "recently_changed_jobs", "type": "=", "value": true }
]
},
"config": { "trigger": { "type": "interval", "every_hours": 168 } },
"notifications": [{ "type": "webhook", "url": "https://your-endpoint.example.com/champions" }]
}'Step 3 — output rows: Person — was [role] at [customer] — now [title] at [new company] — landed [date]. Hand off to your outreach tooling for the "congrats, you know us" touch.
步骤1 —— 当前联系人列表。使用筛选曾任职于客户公司且为true的人员:
person_searchrecently_changed_jobsjs
// user query: champions who recently left my customer accounts
const r = await callTool("person_search", {
filters: and_(
in_("experience.employment_details.past.company_website_domain", inputs.customerDomains),
eq("recently_changed_jobs", true),
gte("professional_network.connections", 100),
excludes("experience.employment_details.past.title", "advisor"),
excludes("experience.employment_details.past.title", "investor"),
excludes("experience.employment_details.past.title", "board")
),
fields: ["basic_profile", "experience", "social_handles"],
limit: 50,
});
if (!r.ok) return { error: r.message };
return r.data.profiles.map(p => {
const cur = p.experience?.employment_details?.current?.[0];
const past = p.experience?.employment_details?.past?.[0];
return {
name: p.basic_profile?.name,
was: past?.title,
at: past?.name,
now: cur?.title,
nowAt: cur?.name,
landed: cur?.start_date,
url: profileUrl(p),
};
});注意事项(均经过实际测试):
- 不可用于过滤——请勿尝试。支持的流程是:筛选曾任职于客户公司 +
experience.employment_details.past.end_date,然后读取recently_changed_jobs = true并整理结果。current[].start_date - 原始列表存在噪音——需手动筛选并移除以下内容:内部调动但“新”公司仍是原客户(或其更名后的主体);子公司/收购导致的变动(实体更名或被收购,人员并未实际离开);顾问/投资者/有限合伙人的任期早已结束;近期换工作但与原客户无关的老员工——在发送“恭喜”消息前,需确认原客户是其最近的雇主。
- 可预先过滤大多数顾问/投资者头衔;每个条件对应一个值,需同时添加多个条件。手动筛选可移除剩余的无效数据。
excludes() - 新公司名称从读取(您过滤时使用
current[].name;响应中的键为company_name)。name - 保留最低联系人数量限制;绝不要投影followers字段。
步骤2 —— 监控器(持续运行)。监控器基于纯REST实现,而非代码模式。Person Discovery Watcher会将您刚刚验证的过滤器转换为持续推送的数据源,每周仅推送新匹配结果至您指定的webhook。首次运行可免费获取基线数据(最多5个匹配结果),之后每个新匹配人员消耗0.5个信用额度。
流程:先运行步骤1的搜索并与用户确认列表无误 → 使用相同过滤器构建curl命令 → 展示命令 → 仅在用户明确同意后创建监控器。
bash
curl -X POST https://api.crustdata.com/watch/person/search \\
-H "authorization: Bearer YOUR_API_KEY" \\
-H "x-api-version: 2025-11-01" \\
-H "content-type: application/json" \\
-d '{
"filters": {
"op": "and",
"conditions": [
{ "field": "experience.employment_details.past.company_website_domain", "type": "in", "value": ["customer1.com", "customer2.com"] },
{ "field": "recently_changed_jobs", "type": "=", "value": true }
]
},
"config": { "trigger": { "type": "interval", "every_hours": 168 } },
"notifications": [{ "type": "webhook", "url": "https://your-endpoint.example.com/champions" }]
}'步骤3 —— 输出行格式:联系人姓名 —— 曾在[客户公司]任[职位] —— 现任[职位]于[新公司] —— 入职日期[date]。将结果传递至您的触达工具,发送“恭喜您入职新公司,我们曾有合作”类消息。
SIGNAL PALETTE (offer during intake, composable)
信号指标列表(输入阶段提供,可组合使用)
Growth (headcount %, role-mix growth, revenue band) — Funding (recency, stage, size, investors) — Hiring (the role whose pain you solve, posting surge, tech named in job posts via ) — Content & intent (people/company posting a keyword via , competitor mentions) — People & movement (champion moved, new exec, competitor leavers, customer alumni, same school) — Company events (news, launches, new office via ) — Tech & presence (technographics, software review counts/ratings) — Warmth (mutuals, shared investor, accelerator) — Disqualifiers OUT (layoffs, existing customers, competitors) — Custom AND-rules.
content.description[.]social_post_search_liveweb_search_live增长(员工人数百分比、职位结构增长、营收区间)—— 融资(时效性、阶段、规模、投资者)—— 招聘(您能解决痛点的职位、招聘激增、职位发布中提及的技术,通过的匹配)—— 内容与意向(人员/企业发布的关键词,通过)—— 人员变动(关键联系人离职、新高管入职、竞争对手员工离职、客户公司校友、同校背景)—— 企业事件(新闻、产品发布、新办公室,通过)—— 技术与存在感(技术栈、软件评论数量/评分)—— 熟悉度(共同联系人、共同投资者、加速器背景)—— 排除项(裁员、现有客户、竞争对手)—— 自定义AND规则。
content.description[.]social_post_search_liveweb_search_liveUNIVERSAL RULES
通用规则
- Ask the goal first; confirm scope in one line; then run the recipe, narrating steps.
- Iterate, never dump round-1 results. Show what each refine round dropped and why.
- Free data first. Contact enrichment is opt-in and cost-confirmed before running. is the default for contact info: no base charge, roughly +1 credit business email, +2 personal email, +2 phone, capped at 5 per person; ≤25 URLs per call (
person_contact_enrich+chunk). NarrowparallelMapto cap the spend and readfieldsfor the actual figure. Always quote the ceiling first: "emails for 20 people = at most ~100 credits, go?"credits_remaining - Company enrich (2 credits per returned match, +2 per match if technographics is requested and returned — so 2-4 cr/match) only by +
crustdata_company_ids, after a free identify.exact_match: true - Junk filter always: <100 connections, placeholder headlines, advisors/investors/board, geo/role mismatches.
- Watchers and any external write need an explicit yes.
- Handoff (always ask): a spreadsheet — CSV export (for your sequencer or CRM import) — hand to the account-research skill for deep-dives on the top accounts — or table only.
- Any text you draft (openers, plays, referral scripts): no em dashes, no "delve"/"leverage"/"streamline", no filler. Write like a colleague who knows the account.
- Adapt the layout to the content — never let it hide anything. The brand system is fixed; the layout is not. If real content doesn't fit — a long company or person name, a 12-word title, 200 rows — change the layout, not the content: let the card grow, wrap instead of truncating, drop to one column, widen the column, raise the cap, or give the wide thing its own scroll container. Never solve a fit problem by clipping a card, ellipsing a name, or silently dropping rows. Where a cap really is unavoidable, say so in the UI ("showing the top 50 of 214") so the reader knows what they're not seeing. Look at the rendered output and fix what's cut off before you hand it over.
- Icons in rendered output: Lucide, the dashboard's icon set, inlined as SVG with a stroke. No emojis in artifact UI — the 🔥/🟡/⚪ scoring tiers are for chat; in a rendered artifact they become coloured pills or Lucide glyphs.
currentColor - Logos and photos are free — use them in rendered output. Person photos too: rides in the
basic_profile.profile_picture_permalinkgroupbasic_profilealready returns, so a rendered people list shows faces rather than monograms.person_searchcomes back frombasic_info.logo_permalink, which you already call to resolve every row, and fromcompany_identify'scompany_searchgroup. Base64-inline it as abasic_infoURI: the media CDN serves these asdata:image/jpeg;base64,..., so a remotebinary/octet-streamrenders blank. Fall back to a monogram when a company has none.<img src> - Artifact branding: deliverables are chat-native by default (tables, CSV) — never render an artifact just to render one. But IF the user wants a deliverable as a rendered page or document (an HTML list, a TAM report, a doc), it carries the Crustdata brand lockup in the header or footer: a small uppercase "Powered by" eyebrow plus the official Crustdata wordmark, linking to crustdata.com. The wordmark pair ships in this skill's —
assets/(dark text, for light backgrounds) andcrustdata-logo-light.png(white text, for dark backgrounds), the same files app.crustdata.com's header renders. Base64-inline the theme-appropriate variant at ~17px height (both, theme-switched, on pages with a dark mode) — never hotlink; rendered artifacts cannot fetch remote images. Brand accent:crustdata-logo-dark.png(the product primary;#5547E2on dark grounds). Body font: Geist when embeddable, else the system stack.#8387FF - Every execute response carries +
credits;credits_remaining(free) reports the balance on demand.account_credits
- 先询问目标;用一句话确认范围;然后执行流程,同步告知用户步骤。
- 迭代优化,绝不直接输出首轮结果。展示每一轮优化保留和排除的内容及原因。
- 优先使用免费数据。联系人信息补充需用户主动选择,并在运行前确认成本。是获取联系人信息的默认工具:无基础费用,企业邮箱约+1信用额度,个人邮箱约+2信用额度,电话约+2信用额度,每人上限5个信用额度;每次调用最多处理25个URL(通过
person_contact_enrich+chunk批量处理)。缩小parallelMap范围以控制成本,并读取fields确认实际消耗。始终先告知最高成本:“获取20人的邮箱最多消耗约100个信用额度,是否继续?”credits_remaining - 企业信息补充(每个返回匹配结果消耗2个信用额度;若请求并返回技术栈数据,额外+2个信用额度——即每个匹配结果消耗2-4个信用额度)仅支持通过+
crustdata_company_ids调用,且需先通过免费的exact_match: true识别企业。company_identify - 始终过滤无效数据:联系人数量<100、占位头衔、顾问/投资者/董事会成员、地域/职位不匹配。
- 监控器及任何外部写入操作需用户明确同意。
- 结果交付(始终询问用户):电子表格——CSV导出(用于您的序列器或CRM导入)——传递至account-research技能对Top账户进行深度分析——仅展示表格。
- 您撰写的任何文本(开场白、行动方案、引荐脚本):不要使用破折号,不要使用“深入研究”/“利用”/“优化”等空泛词汇,不要添加冗余内容。撰写风格要像熟悉客户的同事。
- 根据内容调整布局——绝不让内容被隐藏。品牌系统是固定的,但布局可灵活调整。如果真实内容无法适配布局——例如过长的企业/人员名称、12字的职位头衔、200行数据——请调整布局,而非修改内容:让卡片高度自适应、换行而非截断、改为单列布局、加宽列宽、提高行数上限,或为宽内容添加独立滚动容器。绝不要通过裁剪卡片、省略名称或静默丢弃行来解决适配问题。若确实需要设置上限,请在UI中明确说明(例如“显示前50条,共214条”),让用户了解未展示的内容。在交付前查看渲染后的输出,修复所有被截断的内容。
- 渲染输出中的图标:使用Lucide图标(仪表盘的图标集),以内联SVG形式嵌入,使用描边。在生成的UI中不要使用表情符号——聊天中的🔥/🟡/⚪评分等级,在渲染产物中需改为彩色胶囊或Lucide图标。
currentColor - Logo和照片免费使用——请在渲染输出中使用。也可使用个人照片:包含在
basic_profile.profile_picture_permalink返回的person_search分组中,因此渲染的联系人列表可显示头像而非字母组合。basic_profile来自您已调用的basic_info.logo_permalink(用于解析每行数据)和company_identify的company_search分组。将其Base64内联为basic_info格式的URI:媒体CDN以data:image/jpeg;base64,...格式提供这些资源,因此远程binary/octet-stream会显示空白。若企业无Logo,可回退为字母组合。<img src> - 产物品牌标识:交付物默认采用聊天原生格式(表格、CSV)——绝不只是为了渲染而渲染产物。但如果用户需要以渲染页面或文档(HTML列表、TAM报告、文档)形式交付,需在页眉或页脚添加Crustdata品牌标识:小字号大写的“Powered by”前缀 + 官方Crustdata文字商标,链接至crustdata.com。文字商标文件位于本技能的目录中——
assets/(深色文字,适用于浅色背景)和crustdata-logo-light.png(白色文字,适用于深色背景),与app.crustdata.com页眉使用的文件一致。将适配主题的变体Base64内联,高度约为17px(若页面支持深色模式,需同时内联两个变体并根据主题切换)——绝不要使用热链接;渲染产物无法获取远程图片。品牌强调色:crustdata-logo-dark.png(产品主色;深色背景下使用#5547E2)。正文字体:优先使用Geist(若可嵌入),否则使用系统字体栈。#8387FF - 每个execute响应都会包含+
credits;credits_remaining(免费工具)可按需查询余额。account_credits
COST CHEAT SHEET
成本速查表
| Call | Cost |
|---|---|
| Free |
| ~0.03 cr/result |
Count query ( | ~0.03-0.04 cr |
| counts only, ~free |
| 1 cr/query |
| 1 cr/page |
| 1 cr/post — 3 cr/post with |
| no base; cap 5 cr/person |
| 2 cr/returned match; +2 if technographics requested and returned (2-4/match) |
| Person Discovery Watcher | first run free baseline, then 0.5 cr/new person |
| 调用类型 | 成本 |
|---|---|
| 免费 |
| 约0.03信用额度/结果 |
计数查询( | 约0.03-0.04信用额度 |
| 仅返回计数,近乎免费 |
| 1信用额度/查询 |
| 1信用额度/页面 |
| 1信用额度/帖子 —— 开启 |
| 无基础费用;每人上限5信用额度 |
| 2信用额度/返回匹配结果;若请求并返回技术栈数据,额外+2信用额度(2-4信用额度/匹配结果) |
| Person Discovery Watcher | 首次运行免费获取基线数据,之后每个新匹配人员消耗0.5信用额度 |
Tool dependencies
工具依赖
This skill requires:
- Crustdata MCP server (install.crustdata.com/mcp): a single Code Mode MCP exposing ,
list_tools, andget_schema. All Crustdata data tools are reached inside anexecuteplain-JavaScript script viaexecute({ code }). Tools used here:await callTool(name, params),company_search,person_search,company_identify,company_autocomplete,person_autocomplete,job_search,web_search_live,web_enrich_live,social_post_search_live(opt-in),person_contact_enrich(opt-in),company_enrichaccount_credits - Crustdata REST API () for the champion-tracker watcher only — the skill prints a ready-to-run curl; the user supplies their API key and runs it after an explicit yes
api.crustdata.com
本技能需要:
- Crustdata MCP服务器(install.crustdata.com/mcp):一个代码模式MCP,提供、
list_tools和get_schema接口。所有Crustdata数据工具均通过execute中的纯JavaScript脚本,调用execute({ code })访问。本技能使用的工具包括:await callTool(name, params)、company_search、person_search、company_identify、company_autocomplete、person_autocomplete、job_search、web_search_live、web_enrich_live、social_post_search_live(可选)、person_contact_enrich(可选)、company_enrichaccount_credits - Crustdata REST API():仅用于关键联系人追踪器的监控器——本技能会生成可直接运行的curl命令;用户需提供自己的API密钥,并在明确同意后运行该命令",
api.crustdata.com