Import prospects
Outbound sales, autopiloted.
npx -y skills add aitit-inc/leadace --skill import-prospectsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when the user asks to "import prospects", "upload a list", or has tabular contact data (CSV / Excel / SQLite / text) to load. Two modes: save as tenant-only assets (link later via /match-prospects) or link straight to a project.
SKILL.md
11.0 KB, as published. Nobody here has run it
Import Prospects - Bring Your Own List
A skill that imports existing prospect / contact lists (CSV, Excel, SQLite, plain text, etc.) into LeadAce. The MCP server only accepts a canonical CSV (specific columns), so the LLM here is responsible for reading the user's arbitrary file, mapping it to the canonical schema, writing the canonical CSV, and uploading it.
Before starting: Read ${CLAUDE_PLUGIN_ROOT}/references/workspace-conventions.md and follow the cross-cutting conventions there (data storage, MCP error handling, document writes, output discipline).
Two import modes
- Tenant assets only (default for "name card lists" / "old CRM exports" / lists not tied to a single campaign): no
projectIdis sent to the upload tool. Prospects + organizations are saved at the tenant level. Use/match-prospects <project>afterwards to link the right ones into a specific project. - Linked to a project: a
projectIdis sent; every row also carries amatchReasonand is linked to that project viaproject_prospects. Use this when the list was assembled specifically for one campaign.
Inputs
$0— path to the source file (required). Any tabular format works (CSV, TSV, XLSX, XLS, ODS, SQLite, plain text with consistent delimiters).$1— project name (optional). If supplied, default to project-linked mode (still confirm with the user in step 1). Must already exist; create one with/leadace <your-homepage-URL>first.$2— dedup policy:skip(default) oroverwrite. Withskipexisting rows are left alone; withoverwritematched rows have their fields refreshed (and, in project mode, re-linked to the project).
Canonical CSV schema
| Column | Required | Notes |
|---|---|---|
organizationDomain | yes | Apex domain, e.g. acme.com |
organizationName | yes | |
organizationWebsiteUrl | yes | Must be a full URL |
name | yes | Prospect display name (often the org name or department) |
overview | yes | One-paragraph description of the prospect |
websiteUrl | yes | Prospect-specific URL (often == organizationWebsiteUrl) |
matchReason | yes** | Why this prospect is a target. Required only in project-linked mode; ignored in tenant-only mode |
contactName | no | |
department | no | |
industry | no | Exact value from the tpl_industries vocabulary (master document). Rows with any other value are rejected row-level (errorDetails). |
email | no* | |
contactFormUrl | no* | |
formType | no | One of google_forms, native_html, wordpress_cf7, iframe_embed, with_captcha |
snsAccounts.x | no* | |
snsAccounts.linkedin | no* | |
snsAccounts.instagram | no* | |
snsAccounts.facebook | no* | |
platformUrl | no* | External-platform action page (posting/listing URL) contacted in-platform via the platform channel |
notes | no | |
priority | no | Integer 1-5, default 3 |
doNotContact | no | Boolean. 1 / true / yes / on (case-insensitive) → DNC; 0 / false / no / off → not DNC; empty cell omitted. |
country | recommended | ISO 3166-1 alpha-2 (e.g. US, JP). list_country_codes returns the recognized set and which are send-allowed. |
countrySource | no | manual or ai_inferred. Only meaningful with country. |
* At least one of email, contactFormUrl, any snsAccounts.*, or platformUrl is required per row.
** Tenant-only imports may omit the matchReason column entirely. Linking happens later via /match-prospects, which writes a fresh matchReason per project.
Maximum 1000 data rows per import. Split larger files into multiple calls.
Steps
1. Decide the import mode
Use AskUserQuestion to pick between the two modes — do not assume. Default the first option to:
- "Save as tenant assets only" when
$1is empty. - "Link to a project" (with the named project pre-selected) when
$1is provided.
Options:
- Save as tenant assets only — prospects are stored at the tenant level. Use this for name-card / old-CRM / general lead lists where the right project is unclear. Linking happens later with
/match-prospects. - Link to a project — every row is linked to a project via
project_prospects. Use this when the list was assembled for one specific campaign.
If the user picks Link to a project:
- if
$1is given, use it asPROJECT_NAME. - otherwise call
mcp__plugin_leadace_api__list_projectsand ask viaAskUserQuestion(or use the only project if there's just one). - if there are zero projects, abort: "No projects yet. Run
/leadace <your-homepage-URL>first, or re-run this skill in tenant-asset mode."
If the user picks Save as tenant assets only, set PROJECT_NAME = null and skip every project-resolution step below.
2. Read the source file
If $0 is empty, abort and ask the user for a file path.
Inspect the file by extension:
.csv/.tsv/.txt—Readdirectly.xlsx/.xls/.ods— convert to CSV viaBashusing whatever the user's environment has (python3 -c "import pandas; pandas.read_excel('$0').to_csv('/tmp/leadace_import_src.csv', index=False)"is a reasonable default;ssconvertfrom gnumeric works too). If conversion is impossible, tell the user the install hint and abort..sqlite/.db—sqlite3 $0 .schemato see tables, ask the user which table to use (AskUserQuestion), thensqlite3 -header -csv $0 'SELECT * FROM <table>;'- Anything else — try
Readand let the LLM infer the structure
Read enough rows to understand the schema (first ~50 rows is plenty). Do not attempt to read multi-MB files in one shot.
3. Map columns to the canonical schema
For each source column, decide what canonical column it corresponds to. Do not invent data:
- If
organizationDomainis missing but you have an email or website URL, derive the apex domain (e.g.https://blog.acme.com/foo→acme.com). - If
organizationWebsiteUrlis missing, derivehttps://+organizationDomain. - If
websiteUrlis missing, fall back toorganizationWebsiteUrl. - If
overviewis missing, synthesise a one-line description from available fields (industry, name, role) — never leave it blank. matchReasonhandling depends on the mode chosen in step 1:- Tenant-only mode: omit the
matchReasoncolumn entirely from the canonical CSV. Don't ask the user —/match-prospectswill write fresh per-project reasons later. - Project-linked mode: if the source has no usable
matchReason, ask the user once for a default ("Why is this list a fit for this project?") and apply it to every row.
- Tenant-only mode: omit the
country(recommended): map it when the source carries it, withcountrySourcemanual(source/user-given) orai_inferred(you derived it). If the source has no country at all, don't leave it blank silently — fetchlist_country_codes(recognized codes + send-allowed flags) and ask the user once whether to apply one default country to all rows or leave them blank. Present that fetched list; don't invent one.industry: source labels rarely match the controlled vocabulary verbatim — fetchtpl_industriesviamcp__plugin_leadace_api__get_master_documentand map each source value to its closest entry (Otherwhen none fits). Leave the cell blank rather than passing a free-form label through; unmapped values reject the row.doNotContactmapping (important): if the source has any do-not-contact-like column — common names:do_not_contact,dnc,opted_out,opt_out,unsubscribed,unsubscribe,is_unsubscribed,subscribed=false— map it to canonicaldoNotContact. Emit1for truthy values and leave the cell blank for falsy ones. Do not silently drop these rows. They must be imported with the flag set; otherwise/build-listmay rediscover the same organisation later and the user will outreach to someone who already opted out. Truthy:1,true,yes,on,unsubscribed,opted out. Falsy:0,false,no,off,subscribed,active, blank. If the semantics are ambiguous, ask the user once before mapping.- If a row has none of email / contactFormUrl / snsAccounts.* — drop it and report it in the per-row error summary.
If the source has columns you cannot place anywhere, ignore them — do not try to widen the schema.
4. Confirm with the user before uploading
Show the user:
- the import mode chosen (tenant-only vs linked to project
<name>) - the source path and row count detected
- the column mapping you inferred (source column → canonical column)
- if a
doNotContactcolumn was mapped, how many rows will be flagged DNC vs not - any rows you are dropping and why
Ask via AskUserQuestion whether to proceed. If the user wants tweaks, iterate.
5. Write the canonical CSV
Write the canonical CSV to /tmp/leadace_import_<scope>_<timestamp>.csv using Write (use the project name as <scope> for project-linked mode, or tenant for tenant-only mode). Use proper CSV quoting:
- Fields containing
,,", or newlines must be wrapped in"...". - A literal
"inside a quoted field is doubled ("").
Header row must be exactly the canonical column names (case-sensitive).
6. Pick the dedup policy
If $2 is skip or overwrite, use it directly. Otherwise ask via AskUserQuestion:
skip(default, safer) — existing prospects untouchedoverwrite— matched prospects get their fields refreshed (and, in project-linked mode, re-linked to that project)
7. Upload
Read the canonical CSV file back into a string and call mcp__plugin_leadace_api__import_prospects_from_csv:
- Project-linked mode: pass
projectId: PROJECT_NAMEpluscsvTextanddedupPolicy. - Tenant-only mode: omit
projectIdentirely. Pass onlycsvTextanddedupPolicy. Do not pass an empty string — leave the field out.
8. Report
Surface the counts the tool returns:
inserted— newly createdoverwritten— existing prospects updated (only withoverwrite)skipped— duplicates /do_not_contact/ plan limiterrors— rows that failed validation
For non-zero skipped or errors, summarise the top reasons. If the free plan limit was hit, advise the user to upgrade or delete unused projects.
In tenant-only mode, finish by suggesting the next step: Run \/match-prospects <project-name>` to surface the imported prospects that fit a specific project's strategy and link them.`
Leave the canonical CSV at /tmp/leadace_import_*.csv so the user can re-run with a different policy if needed.