Buyer Discovery
Use this skill to turn a product and target market into evidence-backed B2B buyer actions.
Invariant:
Search discovers surfaces, not organizations.
run.db owns structured facts.
Provider JSONL owns raw API audit only.
CSV files and judge_packets.jsonl are projections over run.db facts.
surface_hits is the surviving discovered surface table.
site_classifications is the promotion gate.
Only official_organization_site rows promote to organizations.
relation_judgments judges economic relation only for organizations.
contacts records contact facts; contact fact != lead action.
lead_actions joins relation + contact ownership + contact intent.
Agent owns semantic strategy and ambiguous business judgment.
Scripts own query compilation, execution, extraction, gates, and persisted facts.
Svelte is read-only ops projection.
Workflow
- Ask for scope before running when the user has not already chosen it.
Use request_user_input or ask_user_questions when available. If it is not available, ask directly in plain language and wait.
Question:
你想先快速看一小批结果,还是直接做完整搜索?
Options:
先看少量结果 (Recommended): 约 2-5 分钟。先确认方向对不对,结果不是最终名单。
直接完整搜索: 约 30-90 分钟。覆盖更全,但等待时间更长。
Do not expose API terms such as SERP, crawl, async, depth, domain dedupe, or relation_type in user-facing questions.
- Express search strategy before execution.
Create a strategy template, then edit it when product semantics require better buyer roles, traces, local terms, or negative query terms:
node scripts/buyer_discovery.mjs strategy-template \
--product "electric skateboards" \
--target-market "Australia" \
--out /tmp/strategy.json
Agent strategy shape:
product_terms, application_scenes, buyer_roles, public_traces,
source_priorities, market_terms, local_language_terms, negative_terms
Validate strategy before any network run:
node scripts/buyer_discovery.mjs strategy-validate \
--strategy-file /tmp/strategy.json \
--product "electric skateboards" \
--target-market "Australia" \
--out /tmp/strategy.normalized.json
Use the normalized file for execution. The validator fails on malformed JSON, duplicate keys, wrong field types, and unknown source_priorities. Do not repair strategy by editing run-input.json.
negative_terms are query compile inputs only. Script hard-reject blocklists are structural gates.
- Run the top-level command.
Quick mode automatically searches, filters surfaces, crawls a small time-boxed sample, maps pages, classifies sites, promotes official organizations, judges relation, extracts contacts, and writes lead actions. Do not ask whether to verify after quick mode; quick already does a small site check.
node scripts/buyer_discovery.mjs quick-scan \
--product "electric skateboards" \
--seller-context "China B2B exporter" \
--target-market "Australia" \
--strategy-file /tmp/strategy.normalized.json
Full mode uses the same pipeline with full search settings and broader crawl targets:
node scripts/buyer_discovery.mjs full-search \
--product "electric skateboards" \
--seller-context "China B2B exporter" \
--target-market "Australia" \
--strategy-file /tmp/strategy.normalized.json \
--confirm-full-search
Quick uses DataForSEO Live at low depth and has a default --quick-budget-seconds 120 time box. Full uses DataForSEO Standard async at full depth. Do not hand-edit run-input.json to change scope, path count, depth, or backend.
After quick mode completes, stop and report the partial projection. Never start full-search or set-scope --search-scope full unless the user explicitly confirms the longer run. Do not promise automatic notification unless a durable automation or thread wakeup was actually created.
- Report progress while running.
Always report stable milestones in plain language:
- start: exact
run_dirand expected duration; - search finished: organic rows and discovered surfaces, not buyers;
- site checks finished or time-boxed: official organizations, source sites, unknown/noise surfaces;
- contacts/actions ready:
lead_actions.csvpath and top rows; - partial state:
status.partial,status.partial_reasons, and pending provider task count; - visible failures:
status.error_count,status.failed_provider_tasks, andstatus.top_errors.
If no milestone changes for 30-60 seconds in quick mode, or 3-5 minutes in full mode, run:
node scripts/buyer_discovery.mjs status --run-dir /tmp/buyer-discovery/<run-id>
Vocabulary is strict:
surface_hits = discovered website/page surfaces
organizations = official organizations after site classification
lead_actions = actionable contact recommendations
Do not call a row a high-value buyer before it appears in lead_actions.
- Use lower-level commands only for recovery or debugging.
node scripts/buyer_discovery.mjs init-run --product "electric skateboards" --target-market "Australia" --search-scope quick
node scripts/buyer_discovery.mjs compile-paths --run-dir /tmp/buyer-discovery/<run-id> --strategy-file /tmp/strategy.json
node scripts/buyer_discovery.mjs serp-submit --run-dir /tmp/buyer-discovery/<run-id>
node scripts/buyer_discovery.mjs serp-poll --run-dir /tmp/buyer-discovery/<run-id> --wait
node scripts/buyer_discovery.mjs surface-filter --run-dir /tmp/buyer-discovery/<run-id>
node scripts/buyer_discovery.mjs crawl-submit --run-dir /tmp/buyer-discovery/<run-id>
node scripts/buyer_discovery.mjs crawl-poll --run-dir /tmp/buyer-discovery/<run-id> --wait
node scripts/buyer_discovery.mjs page-map --run-dir /tmp/buyer-discovery/<run-id>
node scripts/buyer_discovery.mjs site-classify --run-dir /tmp/buyer-discovery/<run-id>
node scripts/buyer_discovery.mjs org-promote --run-dir /tmp/buyer-discovery/<run-id>
node scripts/buyer_discovery.mjs judge-pack --run-dir /tmp/buyer-discovery/<run-id>
node scripts/buyer_discovery.mjs auto-judge --run-dir /tmp/buyer-discovery/<run-id>
node scripts/buyer_discovery.mjs contact-extract --run-dir /tmp/buyer-discovery/<run-id>
node scripts/buyer_discovery.mjs lead-actions --run-dir /tmp/buyer-discovery/<run-id>
node scripts/buyer_discovery.mjs run-learnings --run-dir /tmp/buyer-discovery/<run-id>
- Review or override relation judgments only after reading
references/relation-judge.md.
Every accepted/reviewable relation must cite evidence URLs from official organization pages. Relation judgment must not classify source sites, marketplaces, directories, or content noise; that is the site_classifications table's responsibility.
- Use the read-only UI when useful.
node scripts/buyer_discovery.mjs ui --run-dir /tmp/buyer-discovery/<run-id>
The UI may show discovered surfaces, official organizations, source sites, noise/unknown surfaces, contacts, lead actions, and errors. It must not submit jobs, edit CSV files, or export results.
Outputs
Every run writes run.db as the structured fact store. The authoritative table contract lives in scripts/src/core/db.ts migrations; this markdown describes how agents should consume the projections, but it is not the schema source of truth.
Run projections and audit files:
run.db
run-input.json
search_strategy.json or external strategy file
search_strategy.normalized.json
source_paths.csv
serp_tasks.jsonl
raw_serp.jsonl
serp_domains.csv
surface_hits.csv
serp_rejected.csv
crawl_tasks.jsonl
crawl_records.jsonl
pages.csv
site_classifications.csv
organizations.csv
judge_packets.jsonl
relation_judgments.csv
contacts.csv
lead_actions.csv
run_learnings.csv
candidates.csv
rejected.csv
serp_tasks.jsonl, raw_serp.jsonl, crawl_tasks.jsonl, and crawl_records.jsonl are raw provider audit streams. CSV files are export/projection surfaces for humans and downstream tools. v4 pipeline consumers must not read generated CSV or judge_packets.jsonl as fact-path input.
Mechanical Rules
- Keep API keys in environment variables only.
- Required variables are shown in
.env.example. - CLI reads local
.env/.env.localfrom current and parent directories, orBUYER_DISCOVERY_ENV=/path/to/.env. - Run
node scripts/buyer_discovery.mjs env-statusbefore network runs. - Do not hard-reject manufacturers/factories in scripts. Classify economic relation from official evidence.
- Treat blocked/403 evidence as
unknownat site classification orinsufficient evidenceat relation judgment, not as buyer rejection. surface_hits.priority_scoreis a mechanical ordering hint from surface filtering, not lead score.source_paths.executedis lifecycle state, not path quality.run_learnings.csvis final reporting only; it must not feed decisions in the same run.state-jsonand the Svelte UI read DB-backed projections only; they must not mutate runs.
References
- Read
references/schemas.mdwhen editing or consuming run files. - Read
references/relation-judge.mdbefore classifying economic relation.
Validation
npm --prefix scripts run typecheck
node scripts/buyer_discovery.mjs self-test
npm --prefix scripts run build
Then run the skill creator validator from the local Codex skill-creator installation.