Agent #001 Β· Research & Market Intelligence

Target Account Scanner

🟑 Growth

Scans firmographic, technographic, hiring, funding, and intent signals to build the ICP-matched target account universe

Build time
0.5-1 day
Primary user
RevOps / GTM Engineer
Primary outcome
Target account universe creation
Deployable pack
Yes: full pack

Adam's take

If you only build one agent this year, build this one. Every downstream agent inherits the quality of the universe it creates, and most teams discover their 'ICP' was three opinions in a trench coat the moment they have to write the config.
Adam Woozeer, founder

Required tools

HubSpotClayn8n

Optional tools

6senseDemandbaseApollo

Expected value

Replaces 10-20 hrs/month of manual account research; consistent ICP coverage

Deployable workflow pack

The full pack includes the agent spec, deployment guide, architecture diagrams, n8n workflow skeleton, Clay template, HubSpot properties, JSON schemas, OpenAPI spec, cost and ROI calculators, demo data, QA checklist, and governance notes.

View pack on GitHub
Full deployment guide β†’Governance & failure modes β†’QA checklist β†’

How to deploy this agent

Most teams define an ICP once, in a slide, and never operationalize it. This agent turns the ICP definition into a versioned, running scan against firmographic, technographic, and intent data, and writes the result back to HubSpot as agent-owned properties.

Core signals

Industry: Matched against exact and adjacent ICP industry lists, not free text.
Employee count: Banded against a target range, with partial credit within 25% of the range.
Revenue: Scored neutral when unknown rather than zero β€” missing data isn’t treated as disqualifying.
Geography: Target regions score full credit; serviceable-but-not-target regions score partial.
Tech stack: Must-have tech and disqualifying (competitor) tech are both checked explicitly.
Hiring signals: Count of open roles in target functions (e.g. RevOps, Sales Development).
Funding signals: Recency of last funding round β€” within 12 months scores higher than within 24.
Intent signals: Third-party intent level (surging / moderate / none) on configured topics.
CRM status: Existing customers and accounts with an open deal are gated out before scoring reaches CRM β€” never re-targeted as net-new.

Input schema

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://deploytheagent.com/schemas/agent-001/input.schema.json",
  "title": "Target Account Scanner β€” Input",
  "description": "One candidate account record entering the scoring step. Enrichment fields may be null (scored neutral or zero per workflow logic); required identity and CRM-gate fields may not.",
  "type": "object",
  "required": ["domain", "company_name", "crm_status"],
  "additionalProperties": false,
  "properties": {
    "domain": {
      "type": "string",
      "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$",
      "description": "Normalized root domain, lowercase, no protocol or www"
    },
    "company_name": { "type": "string", "minLength": 1 },
    "industry": { "type": ["string", "null"] },
    "employee_count": { "type": ["integer", "null"], "minimum": 0 },
    "revenue_usd": { "type": ["integer", "null"], "minimum": 0 },
    "hq_country": { "type": ["string", "null"], "description": "ISO 3166-1 alpha-2" },
    "hq_region": { "type": ["string", "null"] },
    "tech_stack": {
      "type": "array",
      "items": { "type": "string" },
      "default": []
    },
    "hiring": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "open_roles_target_function": { "type": ["integer", "null"], "minimum": 0 },
        "functions": { "type": "array", "items": { "type": "string" } }
      }
    },
    "funding": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "last_round": { "type": ["string", "null"] },
        "last_round_date": { "type": ["string", "null"], "format": "date" },
        "last_round_amount_usd": { "type": ["integer", "null"], "minimum": 0 }
      }
    },
    "intent": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "level": { "type": ["string", "null"], "enum": ["surging", "moderate", "none", null] },
        "topics": { "type": "array", "items": { "type": "string" } },
        "provider": { "type": ["string", "null"] }
      }
    },
    "crm_status": {
      "type": "object",
      "required": ["lifecycle_stage", "has_open_deal"],
      "additionalProperties": false,
      "properties": {
        "lifecycle_stage": { "type": ["string", "null"] },
        "has_open_deal": { "type": "boolean" },
        "is_customer": { "type": "boolean", "default": false }
      }
    },
    "source": {
      "type": "string",
      "description": "Where the candidate came from: apollo, import, web_visitor, manual"
    }
  }
}

Output schema

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://deploytheagent.com/schemas/agent-001/output.schema.json",
  "title": "Target Account Scanner β€” Output",
  "description": "One scored account record leaving the workflow. Written to HubSpot agent-owned properties and included in the Slack digest.",
  "type": "object",
  "required": [
    "domain",
    "icp_match_score",
    "icp_match_band",
    "icp_match_reasons",
    "icp_scan_date",
    "icp_model_version",
    "gate_result",
    "score_breakdown"
  ],
  "additionalProperties": false,
  "properties": {
    "domain": { "type": "string" },
    "icp_match_score": { "type": "integer", "minimum": 0, "maximum": 100 },
    "icp_match_band": { "type": "string", "enum": ["Target", "Monitor", "Exclude"] },
    "icp_match_reasons": {
      "type": "array",
      "items": { "type": "string" },
      "minItems": 1,
      "description": "One line per scoring dimension, with source attribution"
    },
    "icp_scan_date": { "type": "string", "format": "date" },
    "icp_model_version": {
      "type": "string",
      "description": "Config version plus prompt version when LLM reasons are enabled, e.g. icp-config-1.0.0/reasons-off"
    },
    "gate_result": {
      "type": "string",
      "enum": ["written", "skipped_customer", "skipped_open_deal", "skipped_excluded_domain"],
      "description": "Whether the record was written to CRM or suppressed, and why"
    },
    "score_breakdown": {
      "type": "object",
      "required": ["firmographic", "technographic", "signals"],
      "additionalProperties": false,
      "properties": {
        "firmographic": { "type": "integer", "minimum": 0, "maximum": 55 },
        "technographic": { "type": "integer", "minimum": 0, "maximum": 15 },
        "signals": { "type": "integer", "minimum": 0, "maximum": 30 }
      }
    },
    "confidence": {
      "type": ["number", "null"],
      "minimum": 0,
      "maximum": 1,
      "description": "Share of scoring fields that were non-null; low confidence flags enrichment gaps, not bad fit"
    }
  }
}

Scoring / classification logic

Firmographic (industry, employee count, revenue, geography): Up to 55 of 100 points
Technographic (must-have and disqualifying tech): Up to 15 of 100 points
Signals (hiring, funding, intent): Up to 30 of 100 points

Accounts scoring 70+ land in the Target band and get written to HubSpot. 50-69 is Monitor. Below 50 is Exclude. Every scoring reason is logged per account with source attribution, and the config version is stored alongside the score so a team can trace exactly which weights produced a given result.

HubSpot CRM properties

icp_match_score company
0-100 ICP match score written by Agent #001 Target Account Scanner. Agent-owned; do not edit manually.
icp_match_band company
Score band written by Agent #001. Target >=70, Monitor 50-69, Exclude <50.
icp_match_reasons company
One line per scoring dimension with source attribution. Written by Agent #001.
icp_scan_date company
Date of the most recent scan that scored this account. Staleness alert fires if no scan in 8 days.
icp_model_version company
ICP config version and prompt version used for this score. Required for auditability.

n8n workflow skeleton

Weekly ICP scan: pull candidates from Clay, score against ICP config, gate on CRM status, write agent-owned HubSpot properties, post Slack digest. Configure every node marked CONFIGURE in its notes.

  1. Weekly scan trigger
    CONFIGURE: default Monday 06:00. First universe build: run manually.
  2. Load ICP config
    CONFIGURE: paste your versioned icp-config JSON here or fetch from repo raw URL. Version string flows to icp_model_version.
  3. Fetch candidates from Clay
    CONFIGURE: Clay table webhook/HTTP API URL and {{CLAY_API_KEY}}. Expects rows matching clay-template.csv headers.
  4. Validate against input schema
    Drops rows failing schemas/input.schema.json shape; logs drops. Do not silence the log.
  5. Score ICP match
    Implements the scoring table from agent-spec.md. Weights come from config, not code edits.
  6. CRM status gate
    Suppression first: customers and open-deal accounts are never written. Gate failures block the run rather than passing records through.
  7. Write agent-owned properties
    CONFIGURE: {{HUBSPOT_CREDENTIAL}}. Writes ONLY the five icp_* properties from hubspot/properties.json. Batch 100 per call. Only gate_result=written records reach this node (add an IF node filter on import if your n8n version needs it explicit).
  8. Post Target-band digest
    CONFIGURE: {{SLACK_CREDENTIAL}} and channel. Digest lists new Target-band accounts with score, top reasons, and a review link. Humans approve before any outbound use.
  9. Write run log
    Audit trail: run date, config version, counts per band, per-field fill rates, gate skips. Alert if Target band >25% of universe or no run in 8 days (pair with a separate monitor workflow).

Agent-driven Clay integration (optional)

The default deployment path pulls Clay data through a static export URL, shown above. Teams already running Clay through its official CLI/MCP (clay-run/agent-plugins) can use this agent-driven path instead.

Clay MCP/CLI Integration β€” Agent #001

Pack Version: 1.0.0

Optional path. Use this instead of a manual `clay-template.csv` import when the n8n workflow's `Fetch candidates from Clay` node should pull from the `to_scanner` view through the official Clay CLI/MCP rather than a static export URL.

Source: `clay-run/agent-plugins` (github.com/clay-run/agent-plugins), the official Clay plugin for Claude Code, Cursor, and Codex. Bundles a `clay` CLI and an MCP server, authenticated with a `CLAY_API_KEY`.

When to use this

The scanner's n8n workflow calls Clay on every scheduled run to read the `to_scanner` view. If that call runs through an agent runtime (n8n's HTTP node hitting the Clay API directly already works and stays the default), the MCP/CLI path is worth it only when the same runtime also needs to trigger Clay-side actions beyond a read: re-running enrichment on a subset, adding rows from a new candidate source, or checking `clay whoami` as a pre-flight credential check before a scheduled run.

If the workflow only reads the `to_scanner` view on a schedule, the existing HTTP export pulls that off with no added dependency. Don't add this file's setup to a deployment that doesn't need it.

Setup

  1. Create a Clay API key: Clay β†’ Settings β†’ Account.
  2. Store it as `CLAY_API_KEY` in the n8n credential store, scoped to this workflow. Never place it in the workflow JSON or the repo.
  3. Install the plugin in the build environment: `/plugin marketplace add clay-run/agent-plugins` then `/plugin install clay@clay-plugins` (Claude Code), or the Codex/Cursor equivalents in the plugin README.
  4. Verify before first production run: `clay whoami`. Exit 0 confirms the key resolves to the correct workspace. Exit 3 means the key is missing or invalid.

Scope for this agent

  • Read `to_scanner` view: unattended, matches the existing governance flags for this agent.
  • Trigger re-enrichment on `pre_filter = pass` rows: unattended, same cost profile as the scheduled enrichment refresh already documented in `clay-setup-guide.md`.
  • Add new candidate rows from a source the agent discovers on its own: not allowed. Candidate sourcing stays a deliberate step a human configures, consistent with `no_auto_crm_writes_without_review` in this agent's Governance section.

Governance addition

Log every Clay CLI/MCP call this workflow makes (view, action, row count, timestamp) alongside the existing `audit_trail_required` flag. Rotate `CLAY_API_KEY` if the n8n instance or its execution logs are ever exposed.

Fallback

The default deployment path stays the CSV export view described in `clay-setup-guide.md`. This file documents the agent-driven alternative for teams already running Clay through its official CLI/MCP elsewhere in their stack.

Cost calculator

Cost Calculator β€” Agent #001

Pack Version: 1.0.0

Cost drivers

DriverUnitTypical priceNotes
Firmographic enrichmentcredit/row$0.05–$0.15Clearbit/Apollo via Clay credits
Tech stack detectioncredit/row$0.05–$0.10BuiltWith/Wappalyzer
Hiring scrapecredit/row$0.02–$0.05Clay native
Funding lookupcredit/row$0.05–$0.10Crunchbase/Harmonic
Intentcontract$15K–$60K/yrOnly if 6sense/Demandbase already owned; don't buy it for this agent
n8ninstance$0–$50/moSelf-hosted or starter cloud
LLM reasons (optional)tokens/row~$0.001–$0.005Off by default; rule-generated reasons are free

Assumptions: Clay credits at blended ~$0.07/credit on a Pro plan; 4 paid enrichment column groups per row on first run; 30-day cache on firmographics, weekly rerun on hiring only (~25% of rows re-enriched per month after month one).

Worked scenarios (monthly, steady state after initial build)

100 records/mo1,000 records/mo10,000 records/mo
New-row enrichment (4 credits Γ— $0.07)$28$280$2,800
Weekly hiring refresh on existing universe$6$56$560
n8n$0–$50$0–$50$50
Total (ex-intent, ex-seats)~$34–$84~$336–$386~$3,410

First-run cost for the initial universe equals the new-row line at your full universe size (e.g. 5,000 candidates β‰ˆ $1,400). The pre-enrichment filter in the Clay guide is the lever: filtering 40% of raw candidates before enrichment cuts these numbers by 40%.

What this replaces

10–20 operator hours/month at a loaded $75/hr = $750–$1,500/month. The crossover argument lives in `roi-calculator.md`.

ROI calculator

ROI Calculator β€” Agent #001

Pack Version: 1.0.0

Fill the blanks with your numbers. Defaults are conservative; the model claims time savings and list quality, not revenue you can't attribute.

Time savings

InputDefaultYours
Hours/month building and refreshing lists today12___
Loaded hourly cost of that operator$75___
Hours/month reviewing scanner output instead2___
Monthly time saving(12 βˆ’ 2) Γ— $75 = $750___

Running cost

InputDefaultYours
Monthly enrichment + tooling (from cost-calculator.md)$386 (1,000 rec/mo)___
Build cost amortized over 12 months (1 day Γ— $600 / 12)$50___
Monthly cost$436___

Net and break-even

Default: $750 βˆ’ $436 = $314/month net, break-even in month 1 including build cost. At 100 records/month the default nets ~$616/month; at 10,000 records the time-saving argument alone doesn't carry it and the case must rest on list quality (below) β€” say so honestly in your business case.

List quality (model only if you can measure it)

Poor-fit accounts entering sequences waste SDR time and depress reply rates. If you can measure your current poor-fit rate:

InputYours
Accounts worked/month___
% outside ICP today___
SDR hours per worked account___
Hours redirected to Target-band accounts= accounts Γ— poor-fit % Γ— hrs

No default here. If you can't measure your poor-fit rate yet, leave this section out of the business case rather than inventing a benchmark.

Governance notes

Failure modes

QA checklist

QA Checklist β€” Agent #001

Pack Version: 1.0.0

Complete on a test HubSpot portal or sandboxed property group before production. The reviewer must not be the builder.

Data validation

  • ☐ All four demo-data records pass `schemas/input.schema.json`
  • ☐ Workflow output on demo data matches `demo-data/sample-output.json` field for field (scores, bands, breakdowns, gate results)
  • ☐ Output validates against `schemas/output.schema.json`
  • ☐ A row with null revenue scores neutral (5), not zero
  • ☐ A row missing a required field is dropped and logged, and does not fail the run

Scoring

  • ☐ Weights in the running config match the agreed, versioned ICP config
  • ☐ Acme Analytics scores 88 / Target; Petal & Stem scores 10 / Exclude
  • ☐ Band thresholds read from config: changing target threshold to 80 demotes Acme without a code edit
  • ☐ Disqualifying tech sets the flag and zeroes the 5-point component

Gates and CRM safety

  • ☐ Northwind Logistics (customer) returns `skipped_customer` and produces no HubSpot write
  • ☐ An account with an open deal returns `skipped_open_deal` and produces no write
  • ☐ Writes land only in the five `icp_*` properties; diff a test company's full property set before/after to confirm
  • ☐ Private app scopes limited to companies read/write + deals read
  • ☐ `icp_model_version` populated on every written record

Operations

  • ☐ Slack digest posts to the agreed channel with score and reasons per account
  • ☐ Run log records band distribution and gate skips
  • ☐ Target band ≀25% of test universe (if higher, weights are too generous; stop and retune)
  • ☐ Duplicate domain in source data scores once, not twice
  • ☐ Rollback tested: workflow disabled, test property values cleared

Sign-off

RoleNameDate
Builder
Reviewer (not the builder)
RevOps owner (ICP config)

FAQ

What data sources does the Target Account Scanner use?
Firmographic and technographic data sourced via Clay (Clearbit, Apollo, BuiltWith), plus optional third-party intent data. All sources are configurable per deployment.
Does this agent create new CRM records?
No. It scores existing accounts and writes scoring fields to HubSpot. Contact-level sourcing is handled by the Prospect List Builder (Agent #005).
How often should the scanner run?
Weekly by default. The first run building the initial universe is typically triggered manually rather than waiting for the schedule.
What happens to accounts that don’t meet the ICP threshold?
They’re scored and logged with full reasoning, landing in the Monitor or Exclude band. Nothing is deleted, so the data is available if ICP criteria change later.

Related agents