lead-qualify
Skill2 starsChanged 41 days agoMITView on GitHub
Check & fill a lead list — yours or one /lead-search built. Re-checks each row against the open web, fills the gaps it can actually observe (website, decision maker, contact channel), and keeps or cuts each row with a reason and fresh evidence. Never a score. (localstack)
3 other projects use a version of this.
Adopted by
Most recently taken up by
- runxhq/runxtheir own version, first seen Oct 13, 2026
- etrebels/claude-code-growth-ostheir own version, first seen Sep 14, 2026
- kronus-tech/kronustheir own version, first seen Mar 30, 2026
Other versions3 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 3
- runxhq/runx★ 97same name
- etrebels/claude-code-growth-os★ 21same name
- kronus-tech/kronus★ 4same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository24 other files it gives its agents.
- competitor-watchSkill
- fact-checkSkill
- file-tidySkill
- inbox-triageSkill
- keyword-researchSkill
- lead-draftSkill
- lead-exportSkill
- lead-planSkill
- lead-reachSkill
- lead-retroSkill
- lead-searchSkill
- localstackSkill
- market-researchSkill
- money-reportSkill
- on-page-optimizerSkill
- reconcileSkill
- routine-reportSkill
- routine-setupSkill
- seo-auditSkill
- setup-localbrainSkill
- social-planSkill
- social-postSkill
- support-faqSkill
- support-replySkill
The file
We split this skill into the rules it gives an agent
7 rules. About 0 are common, 2 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 116
Every row gets keep or cut, a reason, and a fresh evidence URL — never a score.
- Very specific: line 126
Pick the topic: If PLAN-*.md files exist, use the one the user named, or the only one, or ask which — or start a new topic when the file is …
- Very specific: line 142
Nothing is dropped: Every column that fits nowhere goes into Notes as <column>: <value>.
- Distinctive: line 172
Fresh evidence or no verdict: Every keep and every cut cites a URL observed THIS session.
- Very specific: line 191
cut: when one failed (the reason names it).
- Very specific: line 293
Every verdict and every filled value a reader can check by opening one URL, and every quote in a check is on its page (web_extract find …
- Distinctive: line 295
No keep with a failed or unknown check.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
When to invoke this skill
Check & fill. Takes a lead list — one /lead-search built, or a file the
user brings — and works through it row by row against the open web:
- Check: does the website resolve and belong to the company, does the decision maker still match a fresh search, does any plan disqualifier fire.
- Fill: blanks and UNKNOWNs it can actually observe — website, location, decision maker, title — and each lead's contact channel, so drafting can start straight away.
Every row gets keep or cut, a reason, and a fresh evidence URL — never a
score. Use after /lead-search, when someone shares a list ("here's my
list", "enrich this", "check my CSV"), or when asked to "qualify", "verify",
or "clean up" a lead list.
Bringing your own file
A shared list comes in whatever shape its author used ("Name, Company, Email, Notes"). Import it before checking:
- Pick the topic. If
PLAN-*.mdfiles exist, use the one the user named, or the only one, or ask which — or start a new topic when the file is a different piece of work. If none exists, do not send the user to/lead-plan: name the topic from the file and the conversation (<niche>-<territory>, or the file's name), and start a shortPLAN-<topic>.md—# Plan: <topic>, then## What we sell,## Who buys (ICP),## Territoryand## Disqualifiers, filled from what the user said andUNKNOWN — ask before draftingotherwise, then the## Stepschecklist withsearchticked as "imported<file>". - Map the columns by meaning onto the list's header:
Company Name,Location,Website,Decision Maker Name,Title,Profile URL,Evidence URL,Confidence,Verdict,Verdict Reason,Verification URL,Verified Date,Channel,Channel Evidence,Reached,Reached Channel,Exported,Notes"Company"/"Business" →Company Name, "URL"/"Domain" →Website, "Contact"/"Name" →Decision Maker Name, "Role" →Title, "LinkedIn" →Profile URL, an email column →Channel(email <address>, withChannel Evidence=user-supplied). Show the mapping in one short list before writing, and ask only if a column is genuinely ambiguous. - Nothing is dropped. Every column that fits nowhere goes into
Notesas<column>: <value>; …. - Imported rows are the user's facts, not observations.
Evidence URL=user-supplied,Confidence=unconfirmeduntil this run checks them. - Merge, never duplicate. A row whose canonical domain is already in
leads-<topic>.csvis merged: blanks filled from the file, nothing overwritten, the difference noted inNotes. A lead is already handled when its canonical domain (stripwww., lowercase) has aReachedorExportedvalue in anyleads-*.csvin this folder, or appears in alead-<domain>brain record (localbrain list --type leadwith a shell, else.brain/context.mdif it exists). Such a row is still imported, but marked inNotesas "already reached or exported" and never queued for drafting.
Say how many rows came in, how many merged, and how many were already handled.
What you read first
- The topic (no file brought): Pick the topic:
ls PLAN-*.md 2>/dev/null. If the user named a topic, usePLAN-<topic>.md. If exactly one PLAN exists, use it. If several exist and the request does not say which, ask the user which one (list them). If none exists, stop and say: "No plan here yet — run /lead-plan first, or bring your own list to /lead-qualify." The topic is the part betweenPLAN-and.md; every other file for it uses the same topic:leads-<topic>.csv. - The list:
leads-<topic>.csv(after an import, if there was one). No list and no file → offer/lead-search, or ask for a CSV path or pasted rows. Never fabricate input. - The plan: its
## Disqualifierssection becomes the cut criteria. No disqualifiers written → check on observability alone (dead domains, aggregator-as-website, decision maker mismatch) and say so in the report. - DESIGN.md, if present — channels to use or avoid; a channel it rules
out is not recorded as the lead's
Channel.
By default only rows with an empty Verdict are checked, so a rerun picks up
just the rows added since. Re-check every row only when the user asks.
Ground rules (non-negotiable)
- Fresh evidence or no verdict. Every keep and every cut cites a URL observed THIS session. The original row's evidence proves what was true then; checking is about now.
- Keep/cut + reason, never a score. A number invented to rank rows is a fabrication with extra steps. The reason sentence does the ranking.
- Cut rows stay in the file. The list keeps every row, its
Verdictfilled — the cut list is as useful as the keep list. - Fill only what you observed. A blank or UNKNOWN becomes a value only
when you read it this session, cited. Never guess an email pattern
(
first@domain.comis fabrication), never construct a profile URL, never "resolve" UNKNOWN by inference. - Open what you cite. A claim rests on a page you opened this session,
never on a search snippet or a memory. Read several pages per
web_extractcall. Gated sites (LinkedIn and the like) only through search results — and a profile URL only when a search returned it; never construct one. - One check per disqualifier, quoted. For every bullet in the plan's
## Disqualifiers, recordpass,failorunknown, with the URL and words copied exactly from that page. keep only when every one passed; cut when one failed (the reason names it); UNKNOWN when any is unknown — never "relaxed" to a keep. Before writing a keep, prove its quotes:web_extractwithfindset to them (find_only: true); a quote the page does not contain is not evidence — fix the check or the verdict. Put the checks inNotes:checks: 1 pass, 2 pass, 3 fail — <url>. - People and titles as stated. A title is copied from a page that says
it ("Owner", "Practice Manager"); never inferred (a founder is not the
owner unless a page says so). Prefer sources from the last two years; a
name only found in an older source gets
Confidencelikelyand the year inNotes. A second contact needs its own source. - Partial is partial. Budget spent at row 30 of 50 → the report says 30
checked, 20 unchecked, and the unchecked rows keep verdict
UNKNOWN.
Procedure
1. Load — import the user's file first if there is one (above), then the
list and plan (stage load above is the spec).
Scratch for this run lives in .localstack/work/{date}-{slug}/ — hidden, one directory per run, so a new run never clobbers an earlier one and the folder's top level stays the standard files. Scratch is disposable; old run directories may be deleted freely.
The bar for keep (the user's, 2026-10-03): the row fits the plan exactly — every disqualifier checked and none broken; anything you found that breaks one (acquired, over the size, outside the window, not independent) is a cut, even if the rest is strong — and the person is likely to reply: the right role at that size, with a real channel you observed. No channel, or the wrong person, is a cut or UNKNOWN, never keep. Fewer kept rows that meet this beat a full list that does not.
Close, not padded. A row that misses the bar by one thing — the rival
is adjacent rather than head-to-head, a little over the size, no channel
found yet, the round just outside the window — is close, not keep and not
cut. Its Verdict Reason starts with that one difference ("Close: 230 people,
plan says up to 200"). Close rows are shown to the user as their own group;
they decide which to promote (set to keep) or which rule to loosen. Drafts
and exports use keep rows only. Two or more differences is a cut.
Sort the queue first, when you have a decide tool. One decide call over
leads-<topic>.csv (fields: Company Name, Location, Website, Title, Notes,
Evidence URL) with one yes/no question per Disqualifier — "Does the row's own
text show it breaks this rule: <the rule, word for word>?" — and the plan's
size and territory as context. A row with a sure yes (not marked ?) is
checked first and only for that rule, on its Evidence URL: confirmed and
quoted, it is a cut; not confirmed, it gets the full check below. decide
never keeps a row and never cuts one on its own word: it only orders the work.
No decide tool: skip this.
2. Check and fill each queued row (stage verify is the spec). With a
task tool, give the rows to helpers, 3 to 5 rows each, up to 6 at once —
the rows in the brief, read: the plan file, done_when: every row has a
Verdict with its evidence, returns: the finished rows — then write the
returned rows in place: website is
their own domain and alive; every disqualifier checked on a page you opened,
quoted (rule 6); the decision maker and title read from a page that states
them (rule 7); an observed contact channel found where one exists; blanks
filled only from observations. Write each row's result into
leads-<topic>.csv as soon as it is checked — a long run never holds its
findings in memory or scratch only.
3. Write the results in place.
leads-<topic>.csv— on each checked row, fillVerdict(keep,cutorUNKNOWN),Verdict Reason,Verification URL,Verified Date, andChannel/Channel Evidencewhen a channel was observed; replace blanks or UNKNOWNs only with observed values. The row count and order never change.PLAN-<topic>.md— add a dated section after## Steps:
## Qualify — YYYY-MM-DD
kept N / cut M — cuts by reason: <reason>: n, ...
filled: F values (websites w, decision makers d, channels c)
no observed channel: (kept rows without one), or "none"
could not verify: (rows left UNKNOWN and why — budget, ambiguity, dead
trails), or "none"Standard files. This folder is kept in files any agent already reads. Update them in place; never scatter output into new folders.
- AGENTS.md — create it if missing. localstack owns only the block between
<!-- localstack:start -->and<!-- localstack:end -->; rewrite that block, never anything outside it. The block says what this folder is for, the rules (drafts only; nothing is sent without the user's explicit yes, one message at a time; no invented facts), a map of the files below, and one line per topic (its PLAN, its lead count, the next unticked step) and per report (its file and date). - PLAN-
<topic>.md — in## Steps, tick- [x] qualify(add today's date after it) once this step is done; leave it unticked if you stopped partway, and say why in CHANGELOG.md. - CHANGELOG.md — create it if missing (
# Changelog). Add one bullet for this run under today's## YYYY-MM-DDheading, newest date first: the skill, the topic, and the counts or outcome (e.g.- lead-search austin-dentists: 18 found, 3 skipped as already contacted). - TODOS.md — create it if missing (
# TODOs). Add each open next action as- [ ] <action> (<topic>); tick items this run finished; never delete lines. - DESIGN.md — decisions meant to last (positioning, tone, channels to use or avoid). Read it before writing anything a person will see; add to it only when the user states or approves a decision.
For this step: the CHANGELOG line gives kept / cut / filled counts (and
"imported N rows from <file>" when there was an import); add
- [ ] draft outreach for N kept leads (<topic>) to TODOS.md, and one TODO
per kept row with no observed channel.
4. Report and hand off. In chat: the strong (keep) rows, then the close
rows as their own group with each one's difference, then the cut count —
and ask once whether to promote any close rows or loosen the rule most of
them miss. Then: kept/close/cut counts, what was filled, the
dominant cut reasons, what could not be checked. Then offer the next stage —
"Draft outreach for the kept rows with /lead-draft?" — as a structured
question where the runtime supports one, plain text otherwise. On yes, invoke
/lead-draft if this runtime can invoke skills directly (Claude Code:
the Skill tool); otherwise tell the user to type /lead-draft (Codex:
$lead-draft).
Quality bar
- Every verdict and every filled value a reader can check by opening one URL,
and every quote in a check is on its page (
web_extract findsaid so). - No keep with a failed or unknown check.
- A cut without a reason, or a keep without fresh evidence, is a failed row — fix it or mark it UNKNOWN.
- An imported file loses nothing: every source column is in a header column
or in
Notes. - The verdict distribution is honest: a pass that keeps everything checked nothing.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

