sales-research · diff
git:20260918.2429d96 to git:20260920.b0ed958
167 added, 80 removed. Audit A to A.
---
name: sales-research
description: >-
Runs AI background research on a company (and optionally a contact) in the
- Zynkr platform CRM and writes a concise, sales-context zh-TW brief into the
- company's 備註/description field. This is a Claude Code stand-in for the
- platform's own "AI 背景研究" button (app/lib/ai/research.ts) — that feature
- only exists in the platform.zynkr.ai web UI and is NOT exposed through the
- connected `zynkr` MCP server, which only offers CRUD tools (create_company,
- create_contact, update_company, etc.), so there is no MCP call to trigger it
- directly. This skill closes that gap by doing the same job — targeted web
- research (what the company does, industry, size/HQ, notable facts, and why
- they might need Zynkr) — then writing the result back via update_company /
- create_company. Trigger EAGERLY whenever Peter says "trigger company
+ Zynkr platform CRM and writes a concise, sales-context zh-TW brief back onto
+ that record as a CRM note (備註) via `mcp__zynkr__create_note`. The research
+ runs on the Claude Code side — WebSearch/WebFetch plus the Taiwan government
+ registry APIs keyed off the 統一編號 — and only the write-back touches the
+ platform, so it spends NO workspace AI quota. The platform's own "AI 背景研究"
+ button and its MCP twin `mcp__zynkr__research_company` do the same job but
+ bill the workspace AI budget; prefer this skill unless Peter asks for that
+ one by name. Trigger EAGERLY whenever Peter says "trigger company
research", "research this company", "研究這間公司", "查一下這間公司背景",
"幫我查一下[公司名]", "look into [company]", "跑一下背景研究", or asks to
research/enrich/look up a company or contact that is or is about to be in
the Zynkr CRM — even if he only names the company and doesn't spell out
"research." Also fire immediately after a company/contact gets created in
this conversation if he asks for research on it in the same breath (e.g.
"create a company for X, also trigger company research"). Do NOT fire
automatically after every company/contact creation on your own initiative —
only when asked, in this call or the next.
category: sales-consultant
project: sales-research
platform: claude
status: Done
author: Peter Tu
sheetId: "2.11"
input: "A company name/domain (and optionally a contact name), or an existing Zynkr CRM company_id / contact_id."
- process: "Resolve the CRM company record → web research (what they do, size/HQ, facts, sales-fit angle) → dated zh-TW brief flagged unverified → append into description (read-merge-write) → optional task note for a named contact → report."
- output: "The company's 備註/description field updated with a dated AI-research brief, plus an optional note-style task on a named contact — never overwriting prior content."
+ process: "Resolve the CRM company record → web research + 統編 registry lookups (what they do, size/HQ, facts, sales-fit angle) → dated zh-TW brief flagged unverified → write back as a CRM note via create_note → optional note on a named contact → report."
+ output: "A dated 🔎 AI 背景研究 note on the company's CRM timeline (crm_activities, kind='note'), plus an optional note on a named contact — additive, never overwriting prior records."
synergy: []
house-style: bound
---
# Sales Research
```bash
npx skills add https://github.com/peter-tu-zynkr/zynkr-skill-builder --skill sales-research
```
Given a company (and optionally a contact) in the Zynkr CRM, this skill runs targeted
web research on it — what it does, size/HQ, notable facts, and a sales-fit angle for
- Zynkr's own products/services — and writes a concise, dated, zh-TW brief into that
- company's 備註 (description) field, flagged as AI-researched and unverified. Trigger it
- whenever Peter asks to research, look into, or check the background of a company or
- contact tied to the CRM.
+ Zynkr's own products/services — and writes a concise, dated, zh-TW brief back as a
+ **note on that record's CRM timeline**, flagged as AI-researched and unverified.
+ Trigger it whenever Peter asks to research, look into, or check the background of a
+ company or contact tied to the CRM.
## Why this exists
- Zynkr's own AI platform (`platform.zynkr.ai`) already has an "AI 背景研究" feature —
- a button on the company/contact/deal detail page that runs a Claude tool-use loop
+ Zynkr's own AI platform (`platform.zynkr.ai`) has an "AI 背景研究" button on the
+ company/contact/deal detail page that runs a Claude tool-use loop
(`app/lib/ai/research.ts`, `generateBrief`: up to 8 web searches, `RESEARCH_MODEL`)
- and saves a zh-TW markdown brief as a CRM note. It's genuinely good, but it's
- **web-UI only** — the connected `zynkr` MCP server (`mcp__zynkr__*`) exposes only
- CRUD tools (create/get/update/list for companies, contacts, deals, tasks, quotes,
- KB) and has no research/enrichment tool to call from here. So from Claude Code
- there's no way to press that button.
+ and saves a zh-TW markdown brief as a CRM note. Since then it has an MCP twin,
+ `mcp__zynkr__research_company`, so the button *can* now be pressed from here.
- This skill is the workaround: it reproduces the *outcome* (a useful, sales-angled
- background brief landing in the CRM) using tools Claude Code already has —
- `WebSearch` / `WebFetch` for the research, `mcp__zynkr__*` for the CRM write —
- without needing the platform's internal research route. Because it's a rebuild,
- not the same audited pipeline, **always label the output as AI-researched and
- unverified** — exactly the posture the platform's own feature takes (an aid to
- the salesperson, not a source of truth).
+ **Prefer this skill anyway.** Both platform-side routes bill the workspace AI
+ quota and cap out at ~8 generic web searches. This skill runs the research on the
+ Claude Code side — where the model and the search budget are already paid for —
+ and touches the platform only for the write-back, which is a plain
+ `create_note` CRUD call. That buys two things: it costs no CRM AI quota, and it
+ can reach sources the platform loop can't, notably the Taiwan government registry
+ APIs keyed off the 統一編號 (see step 2). Use `research_company` only if Peter
+ asks for the platform's own pipeline by name.
+ Because this is a rebuild rather than the audited in-app pipeline, **always label
+ the output as AI-researched and unverified** — the same posture the platform's own
+ feature takes (an aid to the salesperson, not a source of truth).
+
## How this differs from its neighbours
- **sales-outbound** — enriches a contact from a *profile URL the prospect
handed over* (LinkedIn/IG/Threads bio) as one step inside logging a whole DM
conversation as a lead. It doesn't do open-ended company research.
- **consult-intake** — a weekly batch sweep of inbound consulting-inquiry
emails into deals; doesn't research anything.
- **sales-research** (this one) — takes a company (± contact) already in, or
about to enter, the CRM and does dedicated background research on it, on
demand, independent of any particular conversation thread.
If the research turns up that this is a live consulting/demo lead worth a
human follow-up, say so in the report — but don't create deals or tasks beyond
what's described below; that's the calling skill's (or Peter's) job.
---
## Workflow
### 1 · Resolve the CRM company record
You need a `company_id` before you can write anything. Figure out which case
you're in:
- **Given an id directly** (e.g. from earlier in the conversation) → skip to
step 2, no lookup needed.
- **Given a name/domain, record likely exists** → `mcp__zynkr__list_companies`
and match by name/domain (case-insensitive, tolerate spacing/casing
differences). Found → use that id.
- **No match, or Peter is asking you to create the company right now** →
do the research first (step 2), then `mcp__zynkr__create_company` with the
- brief already embedded in `description` from the start — that's one write
- instead of create-then-append. Preview (`confirm` omitted/false), show
- Peter what would be created, then re-call with `confirm: true`.
+ real structured fields you found (name, domain, industry, address, tax_id,
+ employee_count), and land the brief itself as a note in step 4. Do **not**
+ stuff the brief into `description` — see step 4 for why. Preview (`confirm`
+ omitted/false), show Peter what would be created, then re-call with
+ `confirm: true`.
- **Owner** — default to Peter (`mcp__zynkr__whoami` → `owner_id`) unless told
otherwise.
A contact may be named alongside the company (e.g. "research this company for
Christina at JMP"). If so, resolve or note the `contact_id` too — you'll use
it in step 5.
### 2 · Do the research
- Aim for a handful of targeted searches, not an open-ended crawl — this mirrors
- the platform's own cap (max 8 web searches per brief):
+ Two tracks. Run the registry track **first** whenever the company is Taiwanese and
+ you have (or can find) a 統一編號 — it is fast, free, authoritative, and it anchors
+ whatever the web track turns up.
- 1. `WebSearch` the company name (+ domain if known) to find what they do,
- industry, rough size, HQ/location, and any notable recent facts (funding,
- news, leadership).
- 2. If an official site/About page turns up, `WebFetch` it for anything the
- search snippet didn't cover.
+ #### Track A · Government registry, keyed off the 統編
+
+ Take the 統編 from `get_company` → `tax_id`, or find it by company name. Use `curl`,
+ not `WebFetch` — WebFetch summarises through a small model, and a value that
+ overturns a CRM record should come from the raw bytes.
+
+ - **經濟部商業司 公司登記** — the authoritative name (including the 有限 / 股份有限
+ type), 公司狀況, 設立 + 最後核准變更 dates, 資本總額 and 實收資本額, 代表人,
+ registered address:
+ ```bash
+ curl -sS -g 'https://data.gcis.nat.gov.tw/od/data/api/5F64D864-61CB-4D0D-8AD9-492047CC1EA6?$format=json&$filter=Business_Accounting_NO%20eq%20<統編>&$skip=0&$top=1'
+ ```
+ - **董監事 · 所營事業 · 財政部稅籍** — the g0v mirror returns all three in one call,
+ including the shareholding split and the registered business-scope codes:
+ ```bash
+ curl -sS 'https://company.g0v.ronny.tw/api/show/<統編>'
+ ```
+ **所營事業 is the highest-signal field in the whole brief.** It says what the
+ company registered to *do*, which often contradicts how it presents itself — a
+ headhunting firm carrying `I301010 資訊軟體服務業` and `I501010 產品設計業` is
+ building software whatever its website says. 董監事 出資額 ÷ 已發行股份總數 gives
+ you the ownership split, which tells you how short the decision chain is.
+ - **Industry licence registers**, where one applies. Recruitment agencies, for
+ instance, appear in 勞動部's 私立就業服務機構 open data with licence number,
+ expiry and **員工人數** — often the only public headcount that exists:
+ ```bash
+ curl -sSL 'https://apiservice.mol.gov.tw/OdService/download/A17000000J-020013-IFV' # XML
+ ```
+
+ Treat third-party directories (twincn, datagovtw, findcompany, iyp) as leads only.
+ They lag the registry and routinely show superseded company types and addresses —
+ believing one over the registry has already produced a false "登記名稱存疑" flag.
+
+ #### Track B · Web
+
+ A handful of targeted searches, not an open-ended crawl:
+
+ 1. `WebSearch` the company name (+ domain if known) for what they do, recent
+ facts (funding, news, leadership), and anything the registry can't show.
+ 2. If an official site/About page turns up, `WebFetch` it. Many Taiwanese
+ corporate sites sit behind Cloudflare and return 403 with
+ `cf-mitigated: challenge` to both `curl` and `WebFetch` — when that happens,
+ say the claim is unverified rather than repeating it as fact. Check with
+ `curl -sS -D - -o /dev/null <url> | grep -i cf-mitigated` so the report can
+ state *why* it failed.
3. If a contact was named, one more search on their name + company for
role/background — skip if nothing surfaces, don't guess.
4. Think about the **sales-fit angle**: given what Zynkr sells (an AI platform
with CRM/knowledge-base/automation features, plus AI-adoption consulting
- and training), why might *this* company plausibly be interested? Ground
- this in what the research actually surfaced (e.g. "manages a lot of manual
- CRM upkeep," "recently scaling a sales team," "reliant on spreadsheet
- workflows") — don't invent a pain point that wasn't evidenced.
+ and training), why might *this* company plausibly be interested? Ground it in
+ what the research actually surfaced. The registry is especially good for this:
+ a tiny headcount next to a self-built software product is a structural
+ capability gap, and that gap is the opening.
If the research comes up thin (obscure company, no useful web presence), say
so plainly in the brief rather than padding it with generic filler.
### 3 · Structure the brief
Write in zh-TW, matching the platform's own tone — compact, sales-oriented,
not a Wikipedia dump. Use this shape:
```markdown
- ### 🔍 AI 背景研究 — <YYYY-MM-DD>
- **公司概況:** 一兩句話:做什麼、產業、規模/總部
- **值得注意:** 任何近況、資金、新聞(沒有就省略這行)
- **銷售脈絡:** 為什麼可能對 Zynkr 感興趣的推論——扣緊研究中實際發現的線索
- **聯絡人備註:** <僅在有指定聯絡人時才寫> 角色/背景
+ 🔎 AI 背景研究
+
+ **<主題> — <YYYY-MM-DD>**|統編 <統編>
+
+ **一句話:** 一句話講完最會改變接觸方式的那件事
+
+ **公司登記(<來源>)** 查得到出處的硬事實:名稱 · 狀態 · 資本 · 地址 · 董監事
+ **所營事業** 登記碼 + 中文名,特別是與自我定位不符的那幾項
+ **其他官方登記** 稅籍 · 產業許可(含員工人數、許可效期)
+ **銷售脈絡** 推論,每一點都扣回上面的事實
+ **本次未能查證** 明說查不到什麼、為什麼查不到
+
⚠️ AI 自動研究,未經人工查證 — 使用前請自行確認
```
- Keep it to a short paragraph or two per section — this goes into a CRM notes
- field someone will skim, not a report.
+ Two rules about this shape:
- ### 4 · Write it into the company record — append, never clobber
+ - **The first line must be exactly `🔎 AI 背景研究`** — that is the marker the
+ platform's own research writes, so the note reads as one of the family.
+ - **Keep verified fact and inference in separate sections, and name the source
+ on the fact side.** A brief that blends "the registry says 430 萬實收" with
+ "they probably need help productising" is a brief nobody can safely quote.
+ The 未能查證 section is not an admission of failure — it is what stops the
+ next reader repeating an unchecked claim as established.
- The company's `description` field is a shared notes area (address details,
- prior context, etc. may already be there from earlier work). **Always
- read-merge-write:**
+ Keep it to a short paragraph or two per section — someone will skim this on a
+ timeline, not read a report.
- - Existing company: `mcp__zynkr__get_company(id)` → take its current
- `description` → append the new brief below it (separated by a blank line) →
- `mcp__zynkr__update_company(id, description=<merged text>)`, preview then
- `confirm: true`.
- - Brand-new company (step 1's create-now case): just set `description` to the
- brief directly in `create_company` — nothing to merge yet.
+ ### 4 · Write it back as a CRM note — NOT into `description`
- Never pass other fields you're not intentionally changing — `update_company`
- only touches what you pass, so a bare `id` + `description` call leaves
- everything else (address, tax_id, owner, etc.) untouched.
+ **The write target is a note.** This step has gone wrong before, so be blunt
+ about why:
+ - On `platform.zynkr.ai`, **備註 is the note tab** — `crm_activities` rows with
+ `kind='note'`. That is what Peter sees on a record.
+ - `crm_companies.description` is a different thing. The company detail page
+ selects it and then never renders it; the only place it surfaces in the whole
+ UI is the *create company* modal, labelled 說明. After save it is invisible.
+ A brief written there is a brief nobody will ever read.
+ - The platform's own AI 背景研究 writes `crm_activities` too, never `description`.
+
+ So: `mcp__zynkr__create_note(company_id=<id>, subject="AI 背景研究 · <主題> <YYYY-MM-DD>",
+ body=<the brief from step 3>)` — preview first, then `confirm: true`.
+
+ Three mechanics that bite:
+
+ - **`subject` is not rendered for `kind='note'`.** The card shows `body` only.
+ Put everything you want seen in `body` and open it with the literal
+ `🔎 AI 背景研究` line. Still set `subject` — it shows in search and elsewhere.
+ - **Never put the string `⏳ 研究中` in a note body.** The detail page
+ substring-matches it and renders your finished note as a stuck "researching…"
+ spinner with a 停止 button instead of your content.
+ - Notes are additive — no read-merge-write, nothing to clobber. If the record
+ already carries an older brief, write a new note saying what changed and what
+ it corrects rather than rewriting history.
+
+ **Structured fields are a separate and welcome write.** When the research yields
+ a hard value for a column the CRM actually has — `employee_count`, `industry`,
+ `tax_id`, `address`, `domain` — set it with `update_company`, passing only the
+ fields you mean to change. That is how a fact becomes filterable instead of prose.
+
### 5 · Contact-level note (only if a contact was named)
- Contacts have no `description`/notes field in this MCP — the closest
- equivalent is a task. File one via `mcp__zynkr__create_task`:
+ `create_note` takes a `contact_id` too — use it. Do **not** file a task: a task
+ says something needs doing, and this is a record.
- `contact_id`: the resolved contact
+ - `body`: the contact portion of the brief, opening with `🔎 AI 背景研究`, plus a
+ one-line pointer back to the company record's fuller brief
- `subject`: `AI 背景研究 — <contact name> · <YYYY-MM-DD>`
- - `body`: the "聯絡人備註" portion of the brief (plus a one-line pointer back
- to the company record's fuller brief)
- - Leave `due_at` unset — this is a record, not an actionable to-do.
- Preview, then `confirm: true`.
+ Only create a task if the research surfaced something that genuinely needs a
+ human action, and say so in the report.
+
### 6 · Report
Tell Peter what you found and where it landed — a short summary of the brief
plus which record(s) got updated, e.g.:
```
- 研究完成並寫入 CRM 備註:
+ 研究完成,已寫入公司 timeline 的 note:
- **JMP**(公司 id ...)
- - 產業:統計/資料視覺化軟體,SAS 子公司
- - 銷售脈絡:CRM 管理耗時 → 可能對 Zynkr AI 平台的 CRM 自動化功能感興趣
- - 已附加到公司 description(保留原有內容)
+ **天群企管顧問**(公司 id ...)
+ - 登記事實:實收 430 萬 · 員工 4 人 · 所營事業含資訊軟體服務業與產品設計業
+ - 銷售脈絡:4 人編制卻自建 AI 產品 → 缺的是工程與導入量能,賣顧問與訓練而非工具
+ - 已建立 note(timeline 可見);employee_count 一併補進欄位
+ - 未能查證:官網擋自動存取(Cloudflare challenge),產品功能描述沿用前次研究
⚠️ AI 自動研究,未經查證,回覆客戶前請自行確認關鍵事實
```
- If the CRM write actually failed or you had to skip something (e.g. couldn't
- resolve a company_id), say that plainly instead of reporting success.
+ Say plainly what did not land. A failed CRM write, an unresolved company_id, or
+ a central claim that stayed unverified all belong in the report rather than
+ under a success line that papers over them.
---
## Things to be careful about
- **This is a workaround, not the platform's audited pipeline.** Always
include the ⚠️ unverified disclaimer in what you write to the CRM — don't
let a confident-sounding brief get mistaken for a vetted fact.
- **Never fabricate.** If web research doesn't surface something (size,
funding, a contact's role), leave it out rather than guessing.
- - **Never overwrite existing `description` content.** Read before you write,
- every time — this field may hold address/notes from other workflows.
- - **Preview-then-confirm on every CRM write** (`create_company`,
+ - **Write to notes, never to `description`.** The UI never renders that column,
+ so a brief filed there is silently lost — that is exactly how a 09-18 brief
+ and its 09-20 correction both went unseen. Step 4 has the detail.
+ - **Don't spend CRM AI quota unasked.** `mcp__zynkr__research_company` and the
+ in-app button both bill the workspace AI budget. This skill exists to do the
+ same job from the Claude Code side, where it costs nothing.
+ - **The registry outranks the directories.** When twincn/datagovtw/findcompany
+ disagree with 商業司 about a company's name, type or address, 商業司 wins —
+ and name the source you used in the brief.
+ - **Preview-then-confirm on every CRM write** (`create_note`, `create_company`,
`update_company`, `create_task` all require `confirm: true` to actually
apply) — show Peter the preview first if this is a new company being
- created, since that's a bigger commitment than appending a note.
+ created, since that's a bigger commitment than adding a note.
- **Don't create deals, contacts, or companies you weren't asked to create.**
If the company/contact doesn't exist and Peter only asked for "research,"
ask whether he wants it created too rather than assuming.
- **Scope stays research + write-back.** If the findings suggest a real sales
or consulting opportunity, flag it in the report — don't spin up a deal or
hand off to another skill unprompted.
## House style
Writing style is **not owned by this file**. The house voice lives in two Google Docs under
`[@] 寫作指南` (`12DBdFz3SK22ie9im_ThFMI7IBRXsTZsV`), read at runtime:
- 《[2.0] Zynkr 通用風格指南 House Voice》 `10bOIQwRm9Pxwgct4hlwCwK_B4Pipai1HqBPZKzyRHSE` —
the universal core, plus the addendum for this surface
- 《[3.2] 禁用詞清單 Forbidden Words》 `1N5sHLP4qzmmhpCGsi6KElxi1z0MFe4QZ0Q_35T10Uyg`
Read both before producing client- or reader-facing text, and scan the draft against 《[3.2]》
before handing it over. If Drive is unreachable, say so in the output rather than proceeding
unchecked. Never re-implement either list inside this file.