AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Tam Map

skill-revgrowth1-claude-code-skills-tam-map · by Revgrowth1

Build total addressable market databases for any B2B vertical. Multi-source data collection, deduplication, enrichment hand-off. USE WHEN user says "tam-map" OR "TAM map" OR "build TAM" OR "total addressable market" OR "scrape industry" OR "map the market" OR "how many companies" OR "build a lead database" OR "industry database" OR wants to collect business data from multiple sources for a vertic…

No reviews yet
0 installs
31 views
0.0% view→install

Install

$ agentstack add skill-revgrowth1-claude-code-skills-tam-map

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-revgrowth1-claude-code-skills-tam-map)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
5mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Tam Map? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

TAM MAP - Total Addressable Market Builder

Build comprehensive business databases for any B2B vertical by discovering, scraping, and deduplicating data from every available source. Produces a unified, deduplicated CSV ready for enrichment via local-enrich.

Origin: Built for a roofing contractor client - 113K raw records from 20+ sources, deduplicated to 89,562 unique businesses, 20,557 campaign-ready leads at ~$15 total cost.

Script location: ./

The 7 Phases

| Phase | What Happens | Output | |---|---|---| | 1. Source Discovery | Research ALL data sources for the vertical | Source manifest (scored list) | | 1.5. Keyword Expansion | Discover adjacent keywords that share the same TAM | Expanded keyword list | | 2. Config Generation | Build TAMConfig with sources, keywords, NAICS codes | config.json | | 3. Collection | Run scrapers for each source | {source}/businesses.csv per source | | 4. Deduplication | 3-tier dedup: domain -> name+state -> phone | all_sources_deduped.csv | | 4.5. Existing Leads Exclusion | Remove leads already in CampaignPlatform (ALWAYS run, not optional) | net_new_leads.csv | | 5. Enrichment Hand-off | Feed net new CSV into local-enrich pipeline | Campaign-ready leads |


Phase 1: Source Discovery (THE MOST IMPORTANT PHASE)

The quality of the TAM depends on source breadth. For every vertical, research and catalog every available data source across ALL of these categories:

Source Categories Checklist

| # | Category | What to Look For | Example Sources | |---|---|---|---| | 1 | Government/regulatory | State licenses, professional registries, regulatory filings | State contractor boards, SEC, FDA, FCC, state bar associations, Socrata open data portals | | 2 | Federal contracts | Government contract recipients by NAICS | SAM.gov / USASpending.gov (free API, no auth) | | 3 | Industry associations | Trade orgs, certification bodies, member directories | NRCA (roofing), PHCC (plumbing), CompTIA (IT), ABA (legal) | | 4 | Manufacturer/vendor directories | Certified partner/contractor/reseller locators | GAF/Owens Corning (roofing), Kohler (plumbing), Salesforce AppExchange (SaaS) | | 5 | Company databases | Structured business databases searchable by industry | IcyPeas (any vertical), Crunchbase (tech), D&B | | 6 | Local/maps | Geographic business listings | Google Maps via Serper ZIP code mode (local-enrich step 1) | | 7 | Review platforms | Industry-specific review sites | G2/Capterra (SaaS), Clutch (agencies), Thumbtack/Houzz/Porch (home services), TrustPilot | | 8 | Social platforms | Business pages on social networks | Facebook pages, LinkedIn company search | | 9 | Business directories | General business listings | BBB (any B2B), Chamber of Commerce, industry yellow pages | | 10 | Awards/rankings | Recognition and "best of" lists | Inc 5000, Deloitte Fast 500, industry-specific awards, "Top X [vertical] companies" | | 11 | Job boards | Companies actively hiring for vertical-specific roles | Indeed, LinkedIn Jobs - signals active/growing companies | | 12 | Events/conferences | Exhibitor and sponsor directories | Trade show exhibitor lists, conference sponsor pages | | 13 | Investor/funding | Funded companies in the vertical | Crunchbase, PitchBook, AngelList (for tech/SaaS verticals) | | 14 | Open data | Government statistics with company lists | Census Business Patterns, BLS, state open data portals | | 15 | Marketplace/aggregator | Platform-specific directories | HomeAdvisor (home services), Upwork (agencies), AWS Marketplace (SaaS) | | 16 | Academic/research | Industry reports with company lists | Gartner quadrants, Forrester waves, industry census reports |

How to Research Sources

  1. Web search for "{vertical}" site:*.gov database to find government/regulatory sources
  2. Web search for "{vertical}" association directory members to find trade associations
  3. Web search for "{vertical}" certified contractors or "{vertical}" partner directory for manufacturer/vendor directories
  4. Check NAICS codes at https://www.naics.com/search/ - needed for SAM.gov
  5. Check state licensing - search "{vertical}" license {state} for each major state
  6. Check review platforms - which platforms does this vertical use? (G2 for SaaS, Houzz for home services, Clutch for agencies)
  7. Check if IcyPeas has coverage - run a free count query first

Source Manifest Output

Create manifest.json in the output directory:

{
  "vertical": "plumbing",
  "date": "2026-03-22",
  "total_sources": 18,
  "sources": [
    {
      "name": "icypeas_plumbing",
      "category": "company_database",
      "method": "api",
      "url": "https://app.icypeas.com",
      "estimated_records": 30000,
      "has_owner_names": false,
      "has_emails": false,
      "has_addresses": false,
      "has_phone": false,
      "cost_estimate": "IcyPeas credits",
      "priority": 1,
      "notes": "Broad coverage, domains + LinkedIn URLs"
    }
  ],
  "total_estimated_records": 95000,
  "estimated_unique_after_dedup": 45000
}

Priority Scoring

  • Priority 1 (must-have): Sources with owner names baked in (state licenses), broad coverage databases (IcyPeas), Google Maps
  • Priority 2 (high value): Industry association directories, manufacturer certs, BBB, SAM.gov
  • Priority 3 (nice to have): Review platforms, Facebook pages, awards lists, job board signals

Phase 1.5: Keyword Expansion

Before configuring sources, discover adjacent keywords that target the same TAM. The primary keyword alone often misses 30-60% of the market.

How It Works

  1. Start with the primary keyword (e.g., "coffee shop")
  2. Brainstorm adjacent terms that describe the same businesses differently:
  • Synonyms: "cafe", "coffeehouse"
  • Subtypes: "espresso bar", "coffee roaster", "coffee stand"
  • Related: "bakery cafe", "tea and coffee"
  1. Run IcyPeas free count queries for each candidate keyword to estimate incremental volume
  2. Check overlap - many adjacent keywords return 40-70% duplicates. That's fine - dedup handles it. The goal is to catch the 30-60% that only appear under one keyword.

Example: Coffee Shop Expansion

| Keyword | IcyPeas Count | Incremental After Dedup | |---|---|---| | coffee shop | 22,000 | 22,000 (base) | | cafe | 43,000 | ~9,855 net new | | coffee roaster | 9,000 | ~1,703 net new | | espresso bar | 16,000 | ~2,109 net new | | Total | 90,000 raw | ~35,667 unique |

Rules

  • Always run counts before pulling - IcyPeas count queries are free. Don't pull 43K "cafe" records if count shows only 2K.
  • Dedup cross-keyword overlap - use the same dedup pipeline. Adjacent keywords may overlap 40-70%.
  • Run expanded keywords through ZIP scrape too - Google Maps queries for "cafe near [ZIP]" find different businesses than "coffee shop near [ZIP]".
  • Document the expansion - save the keyword -> count -> incremental mapping in the manifest for future builds.

Phase 2: Config Generation

Build a TAMConfig JSON from the manifest. Use the TAMConfig and TAMSource dataclasses:

from tam_config import TAMConfig, TAMSource

config = TAMConfig(
    vertical_name="plumbing",
    keywords=["plumbing", "plumber", "plumbing contractor", "plumbing company", "plumbing repair"],
    naics_codes=["238220"],
    sources=[
        TAMSource(
            name="icypeas_plumbing",
            category="company_database",
            method="api",
            config={"type": "icypeas"},
            estimated_records=30000,
            priority=1,
        ),
        TAMSource(
            name="sam_gov_plumbing",
            category="federal_contracts",
            method="api",
            config={"type": "sam_gov"},
            estimated_records=2000,
            priority=2,
        ),
        # ... more sources
    ],
    generic_filters=["plumbing contractor", "best plumber", "plumber near me"],
    output_dir=os.path.expanduser("./output/plumbing_20260322"),
)
config.save("config.json")

NAICS Code Reference (Common Verticals)

| Vertical | NAICS | Description | |---|---|---| | Roofing | 238160 | Roofing Contractors | | Plumbing | 238220 | Plumbing, Heating, AC Contractors | | Electrical | 238210 | Electrical Contractors | | HVAC | 238220 | (same as Plumbing) | | Landscaping | 561730 | Landscaping Services | | Pest Control | 561710 | Exterminating and Pest Control | | Painting | 238320 | Painting and Wall Covering | | General Construction | 236220 | Commercial Building Construction | | IT Services | 541512 | Computer Systems Design | | Marketing Agencies | 541810 | Advertising Agencies | | Management Consulting | 541611 | Administrative Management Consulting | | SaaS | 511210 | Software Publishers | | Accounting | 541211 | Offices of CPAs | | Legal | 541110 | Offices of Lawyers |


Phase 3: Collection

Automated Sources (lib/ scrapers)

These run automatically via run_tam.py:

| Source Type | Config type | Script | Notes | |---|---|---|---| | IcyPeas | icypeas | lib/icypeas_client.py | Set config.type = "icypeas" | | SAM.gov | sam_gov | lib/sam_gov_client.py | Set config.type = "sam_gov" | | Serper site-scoped | any | lib/serper_scraper.py | Set site_scope + query_templates in config |

Running Collection

# Run all sources
python3 ./run_tam.py config.json

# Run a single source
python3 ./run_tam.py config.json --source icypeas_plumbing

# Skip collection, just dedup
python3 ./run_tam.py config.json --dedup-only

Google Maps (via local-enrich)

For local/service businesses, run Google Maps scraping via the existing local-enrich pipeline:

# Nationwide ZIP code scrape
python3 ./run_pipeline.py \
  --query "plumbing contractor" \
  --zip-file ./data/us_zipcodes.txt \
  --max-results 20 \
  --step 1

# Copy output to TAM MAP source dir
cp ./output/{latest}/businesses.csv \
   ./output/plumbing_20260322/google_maps/businesses.csv

Bespoke Sources (Claude writes per-vertical)

For sources without a reusable scraper (state license DBs, niche directories), Claude writes a one-off script and saves it to sources/{vertical}/. Follow these patterns:

Serper site-scoped scrape (for any website with a directory):

from lib.serper_scraper import run_site_scrape
from lib.api_utils import empty_unified_row, normalize_state

def extract_fn(result, state, keyword):
    row = empty_unified_row()
    row["business_name"] = result.get("title", "").split(" | ")[0].strip()
    row["state"] = normalize_state(state)
    row["raw_source_url"] = result.get("link", "")
    return row

def is_valid_fn(url, title):
    return "/profile/" in url  # Only profile pages

run_site_scrape(
    source_name="bbb_plumbing",
    site_scope="bbb.org",
    query_templates=['site:{site} inurl:profile "{keyword}" "{state}"'],
    keywords=["plumbing"],
    extract_fn=extract_fn,
    is_valid_fn=is_valid_fn,
    output_dir="output/plumbing_20260322/bbb/",
    api_key=os.environ["SERPER_API_KEY"],
)

State license database (requires per-state research):

  • Check if state has an open data portal (Socrata)
  • Check if state has a searchable license lookup
  • Some states expose CSV/API (FL DBPR, CA CSLB, IL Socrata)
  • Some require Selenium (CAPTCHAs, JS SPAs)
  • Owner names from license records are the highest-value free data

Every bespoke scraper MUST output businesses.csv with the unified schema columns.


Phase 4: Deduplication

The dedup engine auto-detects CSV column names and maps them to the unified schema. No hardcoded source mappers needed.

# Run standalone
python3 ./dedup_engine.py output/plumbing_20260322/ \
  --category plumbing

# Or via run_tam.py (runs automatically after collection)
python3 ./run_tam.py config.json --dedup-only

Three-Tier Dedup Algorithm

  1. Tier 1: Domain match - Records with the same normalized domain are merged. Keeps the record with the most populated fields, fills empty fields from duplicates.
  2. Tier 2: Company name + state - Domainless records matched to domain records by normalized company name + exact state.
  3. Tier 3: Phone match - Remaining unmatched records matched by normalized 10-digit phone number.
  4. Internal dedup - Remaining unmatched records deduplicated among themselves by name+state.

Output

  • all_sources_deduped.csv - unified deduplicated master list
  • dedup_stats.json - per-source counts, overlap analysis, dedup rates

Phase 4.5: Existing Leads Exclusion (MANDATORY)

ALWAYS run exclusion before enrichment. Enriching leads that are already in your campaign platform wastes API credits. In one build, exclusion rate was 31.7% - that's 31.7% of enrichment spend saved by running exclusion first.

Removes leads already in CampaignPlatform or Supabase so only net new records proceed to enrichment. Prevents double-contacting prospects and wasting enrichment credits.

How It Works

  1. CampaignPlatform exclusion: Uses async parallel fetcher (aiohttp, 20 concurrent requests) to build domain cache from all leads. First run: ~28 min for 204K leads at 7.9 pages/sec. Subsequent runs use cache (instant, refreshes after 24h).
  2. Supabase exclusion: Queries icp_companies table for all known domains.
  3. Merge: Combines both domain sets into a single exclusion list.
  4. Filter: Removes TAM records whose domain matches the exclusion set.
  5. Output: net_new_leads.csv + exclusion stats in dedup_stats.json.

Usage

# Via run_tam.py (runs after Phase 4 automatically - always use --exclude-existing)
python3 ./run_tam.py config.json --exclude-existing

# Force refresh the CampaignPlatform cache
python3 ./run_tam.py config.json --exclude-existing --refresh-cache

# Standalone (on an existing deduped CSV)
python3 ./lib/existing_dedup.py \
  --tam-csv output/all_sources_deduped.csv \
  --output output/net_new_leads.csv

# Use workspace-specific API key for multi-workspace setups
YOUR_CAMPAIGN_API_KEY=$YOUR_CAMPAIGN_API_KEY python3 ./lib/existing_dedup.py \
  --tam-csv output/all_sources_deduped.csv \
  --output output/net_new_leads.csv

Performance

The async fetcher uses aiohttp with 20 concurrent requests, achieving ~7-8 pages/sec (vs ~0.4/sec sync). For large workspaces:

| Workspace Size | Pages | Sync Time | Async Time | |---|---|---|---| | 79K leads | ~5,300 | ~15-20 min | ~11 min | | 204K leads | ~13,600 | ~95 min | ~28 min |

Output Stats

The exclusion stats show exactly how much TAM is already contacted:

TAM input:              39,721
Excluded (domain):      10,870
Excluded (email):        1,711
Net new leads:          27,140
Exclusion rate:          31.7%

Cache

  • Stored at ./cache/campaign_platform_domains.json
  • Contains all unique domains and emails from CampaignPlatform
  • Auto-refreshes after 24 hours
  • Use --refresh-cache to force rebuild
  • Use workspace-specific API keys - YOUR_CAMPAIGN_API_KEY, YOUR_CAMPAIGN_API_KEY, etc. The generic key may not return all workspaces' data.

Phase 5: Enrichment Hand-off

Pre-Flight Checks (BEFORE starting enrichment)

  1. Check MillionVerifier credits: curl -s "https://api.millionverifier.com/api/v3/credits?api=$MILLIONVERIFIER_API_KEY" -H "User-Agent: YourAgency/1.0" - need ~1 credit per email to verify. Budget for 30-50% of total leads having emails.
  2. Estimate enrichment volume: After exclusion, how many leads need enrichment? If >10K, plan for batched processing.
  3. Check API availability: BlitzAPI, Prospeo, IcyPeas - ensure keys are valid and credits/limits are sufficient.

Adaptive Email Waterfall

For large TAMs (>5K leads), sample before committing to the full waterfall:

  1. Sample 100-200 domains from the net new CSV
  2. Run Step 3 (email finding) on the sample only
  3. **Measure hit rate*

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.